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

"use strict";

const NO_MARKER = 0;
const IN_PROGRESS_MARKER = 1;
const DONE_MARKER = 2;
const DONE_MAYBE_ROOT_CYCLE_MARKER = 3;
const DONE_AND_ROOT_MARKER = 4;

/**
 * @template T
 */
class Node {
	/**
	 * @param {T} item the value of the node
	 */
	constructor(item) {
		this.item = item;
		/** @type {Set<Node<T>>} */
		this.dependencies = new Set();
		this.marker = NO_MARKER;
		/** @type {Cycle<T> | undefined} */
		this.cycle = undefined;
		this.incoming = 0;
	}
}

/**
 * @template T
 */
class Cycle {
	constructor() {
		/** @type {Set<Node<T>>} */
		this.nodes = new Set();
	}
}

/**
 * @template T
 * @typedef {object} StackEntry
 * @property {Node<T>} node
 * @property {Node<T>[]} openEdges
 */

/**
 * @template T
 * @param {Iterable<T>} items list of items
 * @param {function(T): Iterable<T>} getDependencies function to get dependencies of an item (items that are not in list are ignored)
 * @returns {Iterable<T>} graph roots of the items
 */
module.exports = (items, getDependencies) => {
	/** @type {Map<T, Node<T>>} */
	const itemToNode = new Map();
	for (const item of items) {
		const node = new Node(item);
		itemToNode.set(item, node);
	}

	// early exit when there is only a single item
	if (itemToNode.size <= 1) return items;

	// grab all the dependencies
	for (const node of itemToNode.values()) {
		for (const dep of getDependencies(node.item)) {
			const depNode = itemToNode.get(dep);
			if (depNode !== undefined) {
				node.dependencies.add(depNode);
			}
		}
	}

	// Set of current root modules
	// items will be removed if a new reference to it has been found
	/** @type {Set<Node<T>>} */
	const roots = new Set();

	// Set of current cycles without references to it
	// cycles will be removed if a new reference to it has been found
	// that is not part of the cycle
	/** @type {Set<Cycle<T>>} */
	const rootCycles = new Set();

	// For all non-marked nodes
	for (const selectedNode of itemToNode.values()) {
		if (selectedNode.marker === NO_MARKER) {
			// deep-walk all referenced modules
			// in a non-recursive way

			// start by entering the selected node
			selectedNode.marker = IN_PROGRESS_MARKER;

			// keep a stack to avoid recursive walk
			/** @type {StackEntry<T>[]} */
			const stack = [
				{
					node: selectedNode,
					openEdges: Array.from(selectedNode.dependencies)
				}
			];

			// process the top item until stack is empty
			while (stack.length > 0) {
				const topOfStack = stack[stack.length - 1];

				// Are there still edges unprocessed in the current node?
				if (topOfStack.openEdges.length > 0) {
					// Process one dependency
					const dependency =
						/** @type {Node<T>} */
						(topOfStack.openEdges.pop());
					switch (dependency.marker) {
						case NO_MARKER:
							// dependency has not be visited yet
							// mark it as in-progress and recurse
							stack.push({
								node: dependency,
								openEdges: Array.from(dependency.dependencies)
							});
							dependency.marker = IN_PROGRESS_MARKER;
							break;
						case IN_PROGRESS_MARKER: {
							// It's a in-progress cycle
							let cycle = dependency.cycle;
							if (!cycle) {
								cycle = new Cycle();
								cycle.nodes.add(dependency);
								dependency.cycle = cycle;
							}
							// set cycle property for each node in the cycle
							// if nodes are already part of a cycle
							// we merge the cycles to a shared cycle
							for (
								let i = stack.length - 1;
								stack[i].node !== dependency;
								i--
							) {
								const node = stack[i].node;
								if (node.cycle) {
									if (node.cycle !== cycle) {
										// merge cycles
										for (const cycleNode of node.cycle.nodes) {
											cycleNode.cycle = cycle;
											cycle.nodes.add(cycleNode);
										}
									}
								} else {
									node.cycle = cycle;
									cycle.nodes.add(node);
								}
							}
							// don't recurse into dependencies
							// these are already on the stack
							break;
						}
						case DONE_AND_ROOT_MARKER:
							// This node has be visited yet and is currently a root node
							// But as this is a new reference to the node
							// it's not really a root
							// so we have to convert it to a normal node
							dependency.marker = DONE_MARKER;
							roots.delete(dependency);
							break;
						case DONE_MAYBE_ROOT_CYCLE_MARKER:
							// This node has be visited yet and
							// is maybe currently part of a completed root cycle
							// we found a new reference to the cycle
							// so it's not really a root cycle
							// remove the cycle from the root cycles
							// and convert it to a normal node
							rootCycles.delete(/** @type {Cycle<T>} */ (dependency.cycle));
							dependency.marker = DONE_MARKER;
							break;
						// DONE_MARKER: nothing to do, don't recurse into dependencies
					}
				} else {
					// All dependencies of the current node has been visited
					// we leave the node
					stack.pop();
					topOfStack.node.marker = DONE_MARKER;
				}
			}
			const cycle = selectedNode.cycle;
			if (cycle) {
				for (const node of cycle.nodes) {
					node.marker = DONE_MAYBE_ROOT_CYCLE_MARKER;
				}
				rootCycles.add(cycle);
			} else {
				selectedNode.marker = DONE_AND_ROOT_MARKER;
				roots.add(selectedNode);
			}
		}
	}

	// Extract roots from root cycles
	// We take the nodes with most incoming edges
	// inside of the cycle
	for (const cycle of rootCycles) {
		let max = 0;
		/** @type {Set<Node<T>>} */
		const cycleRoots = new Set();
		const nodes = cycle.nodes;
		for (const node of nodes) {
			for (const dep of node.dependencies) {
				if (nodes.has(dep)) {
					dep.incoming++;
					if (dep.incoming < max) continue;
					if (dep.incoming > max) {
						cycleRoots.clear();
						max = dep.incoming;
					}
					cycleRoots.add(dep);
				}
			}
		}
		for (const cycleRoot of cycleRoots) {
			roots.add(cycleRoot);
		}
	}

	// When roots were found, return them
	if (roots.size > 0) {
		return Array.from(roots, r => r.item);
	} else {
		throw new Error("Implementation of findGraphRoots is broken");
	}
};


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

"use strict";

const path = require("path");

/** @typedef {import("../../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("../FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */

/**
 * @template T
 * @typedef {object} IStatsBase
 * @property {() => boolean} isFile
 * @property {() => boolean} isDirectory
 * @property {() => boolean} isBlockDevice
 * @property {() => boolean} isCharacterDevice
 * @property {() => boolean} isSymbolicLink
 * @property {() => boolean} isFIFO
 * @property {() => boolean} isSocket
 * @property {T} dev
 * @property {T} ino
 * @property {T} mode
 * @property {T} nlink
 * @property {T} uid
 * @property {T} gid
 * @property {T} rdev
 * @property {T} size
 * @property {T} blksize
 * @property {T} blocks
 * @property {T} atimeMs
 * @property {T} mtimeMs
 * @property {T} ctimeMs
 * @property {T} birthtimeMs
 * @property {Date} atime
 * @property {Date} mtime
 * @property {Date} ctime
 * @property {Date} birthtime
 */

/**
 * @typedef {IStatsBase<number>} IStats
 */

/**
 * @typedef {IStatsBase<bigint> & { atimeNs: bigint, mtimeNs: bigint, ctimeNs: bigint, birthtimeNs: bigint  }} IBigIntStats
 */

/**
 * @typedef {object} Dirent
 * @property {() => boolean} isFile
 * @property {() => boolean} isDirectory
 * @property {() => boolean} isBlockDevice
 * @property {() => boolean} isCharacterDevice
 * @property {() => boolean} isSymbolicLink
 * @property {() => boolean} isFIFO
 * @property {() => boolean} isSocket
 * @property {string} name
 * @property {string} path
 */

/** @typedef {string | number | boolean | null} JsonPrimitive */
/** @typedef {JsonValue[]} JsonArray */
/** @typedef {JsonPrimitive | JsonObject | JsonArray} JsonValue */
/** @typedef {{[Key in string]: JsonValue} & {[Key in string]?: JsonValue | undefined}} JsonObject */

/** @typedef {function(NodeJS.ErrnoException | null): void} NoParamCallback */
/** @typedef {function(NodeJS.ErrnoException | null, string=): void} StringCallback */
/** @typedef {function(NodeJS.ErrnoException | null, Buffer=): void} BufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (string | Buffer)=): void} StringOrBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (string[])=): void} ReaddirStringCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (Buffer[])=): void} ReaddirBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (string[] | Buffer[])=): void} ReaddirStringOrBufferCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (Dirent[])=): void} ReaddirDirentCallback */
/** @typedef {function(NodeJS.ErrnoException | null, IStats=): void} StatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, IBigIntStats=): void} BigIntStatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, (IStats | IBigIntStats)=): void} StatsOrBigIntStatsCallback */
/** @typedef {function(NodeJS.ErrnoException | null, number=): void} NumberCallback */
/** @typedef {function(NodeJS.ErrnoException | Error | null, JsonObject=): void} ReadJsonCallback */

/**
 * @typedef {object} WatcherInfo
 * @property {Set<string>} changes get current aggregated changes that have not yet send to callback
 * @property {Set<string>} removals get current aggregated removals that have not yet send to callback
 * @property {Map<string, FileSystemInfoEntry | "ignore">} fileTimeInfoEntries get info about files
 * @property {Map<string, FileSystemInfoEntry | "ignore">} contextTimeInfoEntries get info about directories
 */

// TODO webpack 6 deprecate missing getInfo
/**
 * @typedef {object} Watcher
 * @property {function(): void} close closes the watcher and all underlying file watchers
 * @property {function(): void} pause closes the watcher, but keeps underlying file watchers alive until the next watch call
 * @property {function(): Set<string>=} getAggregatedChanges get current aggregated changes that have not yet send to callback
 * @property {function(): Set<string>=} getAggregatedRemovals get current aggregated removals that have not yet send to callback
 * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getFileTimeInfoEntries get info about files
 * @property {function(): Map<string, FileSystemInfoEntry | "ignore">} getContextTimeInfoEntries get info about directories
 * @property {function(): WatcherInfo=} getInfo get info about timestamps and changes
 */

/**
 * @callback WatchMethod
 * @param {Iterable<string>} files watched files
 * @param {Iterable<string>} directories watched directories
 * @param {Iterable<string>} missing watched existence entries
 * @param {number} startTime timestamp of start time
 * @param {WatchOptions} options options object
 * @param {function(Error | null, Map<string, FileSystemInfoEntry | "ignore">, Map<string, FileSystemInfoEntry | "ignore">, Set<string>, Set<string>): void} callback aggregated callback
 * @param {function(string, number): void} callbackUndelayed callback when the first change was detected
 * @returns {Watcher} a watcher
 */

// TODO webpack 6 make optional methods required and avoid using non standard methods like `join`, `relative`, `dirname`, move IntermediateFileSystemExtras methods to InputFilesystem or OutputFilesystem

/**
 * @typedef {string | Buffer | URL} PathLike
 */

/**
 * @typedef {PathLike | number} PathOrFileDescriptor
 */

/**
 * @typedef {object} ObjectEncodingOptions
 * @property {BufferEncoding | null | undefined} [encoding]
 */

/**
 * @typedef {{
 * (path: PathOrFileDescriptor, options: ({ encoding?: null | undefined, flag?: string | undefined } & import("events").Abortable) | undefined | null, callback: BufferCallback): void;
 * (path: PathOrFileDescriptor, options: ({ encoding: BufferEncoding, flag?: string | undefined } & import("events").Abortable) | BufferEncoding, callback: StringCallback): void;
 * (path: PathOrFileDescriptor, options: (ObjectEncodingOptions & { flag?: string | undefined } & import("events").Abortable) | BufferEncoding | undefined | null, callback: StringOrBufferCallback): void;
 * (path: PathOrFileDescriptor, callback: BufferCallback): void;
 * }} ReadFile
 */

/**
 * @typedef {{
 * (path: PathOrFileDescriptor, options?: { encoding?: null | undefined, flag?: string | undefined } | null): Buffer;
 * (path: PathOrFileDescriptor, options: { encoding: BufferEncoding, flag?: string | undefined } | BufferEncoding): string;
 * (path: PathOrFileDescriptor, options?: (ObjectEncodingOptions & { flag?: string | undefined }) | BufferEncoding | null): string | Buffer;
 * }} ReadFileSync
 */

/**
 * @typedef {ObjectEncodingOptions | BufferEncoding | undefined | null} EncodingOption
 */

/**
 * @typedef {'buffer'| { encoding: 'buffer' }} BufferEncodingOption
 */

/**
 * @typedef {object} StatOptions
 * @property {(boolean | undefined)=} bigint
 */

/**
 * @typedef {object} StatSyncOptions
 * @property {(boolean | undefined)=} bigint
 * @property {(boolean | undefined)=} throwIfNoEntry
 */

/**
 * @typedef {{
 * (path: PathLike, options: EncodingOption, callback: StringCallback): void;
 * (path: PathLike, options: BufferEncodingOption, callback: BufferCallback): void;
 * (path: PathLike, options: EncodingOption, callback: StringOrBufferCallback): void;
 * (path: PathLike, callback: StringCallback): void;
 * }} Readlink
 */

/**
 * @typedef {{
 * (path: PathLike, options?: EncodingOption): string;
 * (path: PathLike, options: BufferEncodingOption): Buffer;
 * (path: PathLike, options?: EncodingOption): string | Buffer;
 * }} ReadlinkSync
 */

/**
 * @typedef {{
 * (path: PathLike, options: { encoding: BufferEncoding | null, withFileTypes?: false | undefined, recursive?: boolean | undefined } | BufferEncoding | undefined | null, callback: ReaddirStringCallback): void;
 * (path: PathLike, options: { encoding: 'buffer', withFileTypes?: false | undefined, recursive?: boolean | undefined } | 'buffer', callback: ReaddirBufferCallback): void;
 * (path: PathLike, callback: ReaddirStringCallback): void;
 * (path: PathLike, options: (ObjectEncodingOptions & { withFileTypes?: false | undefined, recursive?: boolean | undefined }) | BufferEncoding | undefined | null, callback: ReaddirStringOrBufferCallback): void;
 * (path: PathLike, options: ObjectEncodingOptions & { withFileTypes: true, recursive?: boolean | undefined }, callback: ReaddirDirentCallback): void;
 * }} Readdir
 */

/**
 * @typedef {{
 * (path: PathLike, options?: { encoding: BufferEncoding | null, withFileTypes?: false | undefined, recursive?: boolean | undefined } | BufferEncoding | null): string[];
 * (path: PathLike, options: { encoding: 'buffer', withFileTypes?: false | undefined, recursive?: boolean | undefined } | 'buffer'): Buffer[];
 * (path: PathLike, options?: (ObjectEncodingOptions & { withFileTypes?: false | undefined, recursive?: boolean | undefined }) | BufferEncoding | null): string[] | Buffer[];
 * (path: PathLike, options: ObjectEncodingOptions & { withFileTypes: true, recursive?: boolean | undefined }): Dirent[];
 * }} ReaddirSync
 */

/**
 * @typedef {{
 * (path: PathLike, callback: StatsCallback): void;
 * (path: PathLike, options: (StatOptions & { bigint?: false | undefined }) | undefined, callback: StatsCallback): void;
 * (path: PathLike, options: StatOptions & { bigint: true }, callback: BigIntStatsCallback): void;
 * (path: PathLike, options: StatOptions | undefined, callback: StatsOrBigIntStatsCallback): void;
 * }} Stat
 */

/**
 * @typedef {{
 * (path: PathLike, options?: undefined): IStats;
 * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined, throwIfNoEntry: false }): IStats | undefined;
 * (path: PathLike, options: StatSyncOptions & { bigint: true, throwIfNoEntry: false }): IBigIntStats | undefined;
 * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined }): IStats;
 * (path: PathLike, options: StatSyncOptions & { bigint: true }): IBigIntStats;
 * (path: PathLike,  options: StatSyncOptions & { bigint: boolean, throwIfNoEntry?: false | undefined }): IStats | IBigIntStats;
 * (path: PathLike,  options?: StatSyncOptions): IStats | IBigIntStats | undefined;
 * }} StatSync
 */

/**
 * @typedef {{
 * (path: PathLike, callback: StatsCallback): void;
 * (path: PathLike, options: (StatOptions & { bigint?: false | undefined }) | undefined, callback: StatsCallback): void;
 * (path: PathLike, options: StatOptions & { bigint: true }, callback: BigIntStatsCallback): void;
 * (path: PathLike, options: StatOptions | undefined, callback: StatsOrBigIntStatsCallback): void;
 * }} LStat
 */

/**
 * @typedef {{
 * (path: PathLike, options?: undefined): IStats;
 * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined, throwIfNoEntry: false }): IStats | undefined;
 * (path: PathLike, options: StatSyncOptions & { bigint: true, throwIfNoEntry: false }): IBigIntStats | undefined;
 * (path: PathLike, options?: StatSyncOptions & { bigint?: false | undefined }): IStats;
 * (path: PathLike, options: StatSyncOptions & { bigint: true }): IBigIntStats;
 * (path: PathLike,  options: StatSyncOptions & { bigint: boolean, throwIfNoEntry?: false | undefined }): IStats | IBigIntStats;
 * (path: PathLike,  options?: StatSyncOptions): IStats | IBigIntStats | undefined;
 * }} LStatSync
 */

/**
 * @typedef {{
 * (path: PathLike, options: EncodingOption, callback: StringCallback): void;
 * (path: PathLike, options: BufferEncodingOption, callback: BufferCallback): void;
 * (path: PathLike, options: EncodingOption, callback: StringOrBufferCallback): void;
 * (path: PathLike, callback: StringCallback): void;
 * }} RealPath
 */

/**
 * @typedef {{
 * (path: PathLike, options?: EncodingOption): string;
 * (path: PathLike, options: BufferEncodingOption): Buffer;
 * (path: PathLike, options?: EncodingOption): string | Buffer;
 * }} RealPathSync
 */

/**
 * @typedef {function(PathOrFileDescriptor, ReadJsonCallback): void} ReadJson
 */

/**
 * @typedef {function(PathOrFileDescriptor): JsonObject} ReadJsonSync
 */

/**
 * @typedef {function((string | string[] | Set<string>)=): void} Purge
 */

/**
 * @typedef {object} InputFileSystem
 * @property {ReadFile} readFile
 * @property {ReadFileSync=} readFileSync
 * @property {Readlink} readlink
 * @property {ReadlinkSync=} readlinkSync
 * @property {Readdir} readdir
 * @property {ReaddirSync=} readdirSync
 * @property {Stat} stat
 * @property {StatSync=} statSync
 * @property {LStat=} lstat
 * @property {LStatSync=} lstatSync
 * @property {RealPath=} realpath
 * @property {RealPathSync=} realpathSync
 * @property {ReadJson=} readJson
 * @property {ReadJsonSync=} readJsonSync
 * @property {Purge=} purge
 * @property {(function(string, string): string)=} join
 * @property {(function(string, string): string)=} relative
 * @property {(function(string): string)=} dirname
 */

/**
 * @typedef {number | string} Mode
 */

/**
 * @typedef {(ObjectEncodingOptions & import("events").Abortable & { mode?: Mode | undefined, flag?: string | undefined, flush?: boolean | undefined }) | BufferEncoding | null} WriteFileOptions
 */

/**
 * @typedef {{
 * (file: PathOrFileDescriptor, data: string | NodeJS.ArrayBufferView, options: WriteFileOptions, callback: NoParamCallback): void;
 * (file: PathOrFileDescriptor, data: string | NodeJS.ArrayBufferView, callback: NoParamCallback): void;
 * }} WriteFile
 */

/**
 * @typedef {{ recursive?: boolean | undefined, mode?: Mode | undefined }} MakeDirectoryOptions
 */

/**
 * @typedef {{
 * (file: PathLike, options: MakeDirectoryOptions & { recursive: true }, callback: StringCallback): void;
 * (file: PathLike, options: Mode | (MakeDirectoryOptions & { recursive?: false | undefined; }) | null | undefined, callback: NoParamCallback): void;
 * (file: PathLike, options: Mode | MakeDirectoryOptions | null | undefined, callback: StringCallback): void;
 * (file: PathLike, callback: NoParamCallback): void;
 * }} Mkdir
 */

/**
 * @typedef {{ maxRetries?: number | undefined, recursive?: boolean | undefined, retryDelay?: number | undefined }} RmDirOptions
 */

/**
 * @typedef {{
 * (file: PathLike, callback: NoParamCallback): void;
 * (file: PathLike, options: RmDirOptions, callback: NoParamCallback): void;
 * }} Rmdir
 */

/**
 * @typedef {function(PathLike, NoParamCallback): void} Unlink
 */

/**
 * @typedef {object} OutputFileSystem
 * @property {WriteFile} writeFile
 * @property {Mkdir} mkdir
 * @property {Readdir=} readdir
 * @property {Rmdir=} rmdir
 * @property {Unlink=} unlink
 * @property {Stat} stat
 * @property {LStat=} lstat
 * @property {ReadFile} readFile
 * @property {(function(string, string): string)=} join
 * @property {(function(string, string): string)=} relative
 * @property {(function(string): string)=} dirname
 */

/**
 * @typedef {object} WatchFileSystem
 * @property {WatchMethod} watch
 */

/**
 * @typedef {{
 * (path: PathLike, options: MakeDirectoryOptions & { recursive: true }): string | undefined;
 * (path: PathLike, options?: Mode | (MakeDirectoryOptions & { recursive?: false | undefined }) | null): void;
 * (path: PathLike, options?: Mode | MakeDirectoryOptions | null): string | undefined;
 * }} MkdirSync
 */

/**
 * @typedef {object} StreamOptions
 * @property {(string | undefined)=} flags
 * @property {(BufferEncoding | undefined)} encoding
 * @property {(number | any | undefined)=} fd
 * @property {(number | undefined)=} mode
 * @property {(boolean | undefined)=} autoClose
 * @property {(boolean | undefined)=} emitClose
 * @property {(number | undefined)=} start
 * @property {(AbortSignal | null | undefined)=} signal
 */

/**
 * @typedef {object} FSImplementation
 * @property {((...args: any[]) => any)=} open
 * @property {((...args: any[]) => any)=} close
 */

/**
 * @typedef {FSImplementation & { write: (...args: any[]) => any; close?: (...args: any[]) => any }} CreateWriteStreamFSImplementation
 */

/**
 * @typedef {StreamOptions & { fs?: CreateWriteStreamFSImplementation | null | undefined }} WriteStreamOptions
 */

/**
 * @typedef {function(PathLike, (BufferEncoding | WriteStreamOptions)=): NodeJS.WritableStream} CreateWriteStream
 */

/**
 * @typedef {number | string} OpenMode
 */

/**
 * @typedef {{
 * (file: PathLike, flags: OpenMode | undefined,  mode: Mode | undefined | null, callback: NumberCallback): void;
 * (file: PathLike, flags: OpenMode | undefined, callback: NumberCallback): void;
 * (file: PathLike, callback: NumberCallback): void;
 * }} Open
 */

/**
 * @typedef {number | bigint} ReadPosition
 */

/**
 * @typedef {object} ReadSyncOptions
 * @property {(number | undefined)=} offset
 * @property {(number | undefined)=} length
 * @property {(ReadPosition | null | undefined)=} position
 */

/**
 * @template {NodeJS.ArrayBufferView} TBuffer
 * @typedef {object} ReadAsyncOptions
 * @property {(number | undefined)=} offset
 * @property {(number | undefined)=} length
 * @property {(ReadPosition | null | undefined)=} position
 * @property {TBuffer=} buffer
 */

/**
 * @template {NodeJS.ArrayBufferView} [TBuffer=Buffer]
 * @typedef {{
 * (fd: number, buffer: TBuffer, offset: number, length: number, position: ReadPosition | null, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void;
 * (fd: number, options: ReadAsyncOptions<TBuffer>, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: TBuffer) => void): void;
 * (fd: number, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: NodeJS.ArrayBufferView) => void): void;
 * }} Read
 */

/** @typedef {function(number, NoParamCallback): void} Close */

/** @typedef {function(PathLike, PathLike, NoParamCallback): void} Rename */

/**
 * @typedef {object} IntermediateFileSystemExtras
 * @property {MkdirSync} mkdirSync
 * @property {CreateWriteStream} createWriteStream
 * @property {Open} open
 * @property {Read} read
 * @property {Close} close
 * @property {Rename} rename
 */

/** @typedef {InputFileSystem & OutputFileSystem & IntermediateFileSystemExtras} IntermediateFileSystem */

/**
 *
 * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
 * @param {string} rootPath the root path
 * @param {string} targetPath the target path
 * @returns {string} location of targetPath relative to rootPath
 */
const relative = (fs, rootPath, targetPath) => {
	if (fs && fs.relative) {
		return fs.relative(rootPath, targetPath);
	} else if (path.posix.isAbsolute(rootPath)) {
		return path.posix.relative(rootPath, targetPath);
	} else if (path.win32.isAbsolute(rootPath)) {
		return path.win32.relative(rootPath, targetPath);
	} else {
		throw new Error(
			`${rootPath} is neither a posix nor a windows path, and there is no 'relative' method defined in the file system`
		);
	}
};
exports.relative = relative;

/**
 * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
 * @param {string} rootPath a path
 * @param {string} filename a filename
 * @returns {string} the joined path
 */
const join = (fs, rootPath, filename) => {
	if (fs && fs.join) {
		return fs.join(rootPath, filename);
	} else if (path.posix.isAbsolute(rootPath)) {
		return path.posix.join(rootPath, filename);
	} else if (path.win32.isAbsolute(rootPath)) {
		return path.win32.join(rootPath, filename);
	} else {
		throw new Error(
			`${rootPath} is neither a posix nor a windows path, and there is no 'join' method defined in the file system`
		);
	}
};
exports.join = join;

/**
 * @param {InputFileSystem|OutputFileSystem|undefined} fs a file system
 * @param {string} absPath an absolute path
 * @returns {string} the parent directory of the absolute path
 */
const dirname = (fs, absPath) => {
	if (fs && fs.dirname) {
		return fs.dirname(absPath);
	} else if (path.posix.isAbsolute(absPath)) {
		return path.posix.dirname(absPath);
	} else if (path.win32.isAbsolute(absPath)) {
		return path.win32.dirname(absPath);
	} else {
		throw new Error(
			`${absPath} is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system`
		);
	}
};
exports.dirname = dirname;

/**
 * @param {OutputFileSystem} fs a file system
 * @param {string} p an absolute path
 * @param {function(Error=): void} callback callback function for the error
 * @returns {void}
 */
const mkdirp = (fs, p, callback) => {
	fs.mkdir(p, err => {
		if (err) {
			if (err.code === "ENOENT") {
				const dir = dirname(fs, p);
				if (dir === p) {
					callback(err);
					return;
				}
				mkdirp(fs, dir, err => {
					if (err) {
						callback(err);
						return;
					}
					fs.mkdir(p, err => {
						if (err) {
							if (err.code === "EEXIST") {
								callback();
								return;
							}
							callback(err);
							return;
						}
						callback();
					});
				});
				return;
			} else if (err.code === "EEXIST") {
				callback();
				return;
			}
			callback(err);
			return;
		}
		callback();
	});
};
exports.mkdirp = mkdirp;

/**
 * @param {IntermediateFileSystem} fs a file system
 * @param {string} p an absolute path
 * @returns {void}
 */
const mkdirpSync = (fs, p) => {
	try {
		fs.mkdirSync(p);
	} catch (err) {
		if (err) {
			if (/** @type {NodeJS.ErrnoException} */ (err).code === "ENOENT") {
				const dir = dirname(fs, p);
				if (dir === p) {
					throw err;
				}
				mkdirpSync(fs, dir);
				fs.mkdirSync(p);
				return;
			} else if (/** @type {NodeJS.ErrnoException} */ (err).code === "EEXIST") {
				return;
			}
			throw err;
		}
	}
};
exports.mkdirpSync = mkdirpSync;

/**
 * @param {InputFileSystem} fs a file system
 * @param {string} p an absolute path
 * @param {ReadJsonCallback} callback callback
 * @returns {void}
 */
const readJson = (fs, p, callback) => {
	if ("readJson" in fs)
		return /** @type {NonNullable<InputFileSystem["readJson"]>} */ (
			fs.readJson
		)(p, callback);
	fs.readFile(p, (err, buf) => {
		if (err) return callback(err);
		let data;
		try {
			data = JSON.parse(/** @type {Buffer} */ (buf).toString("utf-8"));
		} catch (e) {
			return callback(/** @type {Error} */ (e));
		}
		return callback(null, data);
	});
};
exports.readJson = readJson;

/**
 * @param {InputFileSystem} fs a file system
 * @param {string} p an absolute path
 * @param {function(NodeJS.ErrnoException | Error | null, (IStats | string)=): void} callback callback
 * @returns {void}
 */
const lstatReadlinkAbsolute = (fs, p, callback) => {
	let i = 3;
	const doReadLink = () => {
		fs.readlink(p, (err, target) => {
			if (err && --i > 0) {
				// It might was just changed from symlink to file
				// we retry 2 times to catch this case before throwing the error
				return doStat();
			}
			if (err || !target) return doStat();
			const value = target.toString();
			callback(null, join(fs, dirname(fs, p), value));
		});
	};
	const doStat = () => {
		if ("lstat" in fs) {
			return /** @type {NonNullable<InputFileSystem["lstat"]>} */ (fs.lstat)(
				p,
				(err, stats) => {
					if (err) return callback(err);
					if (/** @type {IStats} */ (stats).isSymbolicLink()) {
						return doReadLink();
					}
					callback(null, stats);
				}
			);
		} else {
			return fs.stat(p, callback);
		}
	};
	if ("lstat" in fs) return doStat();
	doReadLink();
};
exports.lstatReadlinkAbsolute = lstatReadlinkAbsolute;

license: mit


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

"use strict";

const Hash = require("../Hash");
const MAX_SHORT_STRING = require("./wasm-hash").MAX_SHORT_STRING;

class BatchedHash extends Hash {
	/**
	 * @param {Hash} hash hash
	 */
	constructor(hash) {
		super();
		this.string = undefined;
		this.encoding = undefined;
		this.hash = hash;
	}

	/**
	 * Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
	 * @param {string|Buffer} data data
	 * @param {string=} inputEncoding data encoding
	 * @returns {this} updated hash
	 */
	update(data, inputEncoding) {
		if (this.string !== undefined) {
			if (
				typeof data === "string" &&
				inputEncoding === this.encoding &&
				this.string.length + data.length < MAX_SHORT_STRING
			) {
				this.string += data;
				return this;
			}
			this.hash.update(this.string, this.encoding);
			this.string = undefined;
		}
		if (typeof data === "string") {
			if (
				data.length < MAX_SHORT_STRING &&
				// base64 encoding is not valid since it may contain padding chars
				(!inputEncoding || !inputEncoding.startsWith("ba"))
			) {
				this.string = data;
				this.encoding = inputEncoding;
			} else {
				this.hash.update(data, inputEncoding);
			}
		} else {
			this.hash.update(data);
		}
		return this;
	}

	/**
	 * Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
	 * @param {string=} encoding encoding of the return value
	 * @returns {string|Buffer} digest
	 */
	digest(encoding) {
		if (this.string !== undefined) {
			this.hash.update(this.string, this.encoding);
		}
		return this.hash.digest(encoding);
	}
}

module.exports = BatchedHash;


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

"use strict";

// 65536 is the size of a wasm memory page
// 64 is the maximum chunk size for every possible wasm hash implementation
// 4 is the maximum number of bytes per char for string encoding (max is utf-8)
// ~3 makes sure that it's always a block of 4 chars, so avoid partially encoded bytes for base64
const MAX_SHORT_STRING = Math.floor((65536 - 64) / 4) & ~3;

class WasmHash {
	/**
	 * @param {WebAssembly.Instance} instance wasm instance
	 * @param {WebAssembly.Instance[]} instancesPool pool of instances
	 * @param {number} chunkSize size of data chunks passed to wasm
	 * @param {number} digestSize size of digest returned by wasm
	 */
	constructor(instance, instancesPool, chunkSize, digestSize) {
		const exports = /** @type {any} */ (instance.exports);
		exports.init();
		this.exports = exports;
		this.mem = Buffer.from(exports.memory.buffer, 0, 65536);
		this.buffered = 0;
		this.instancesPool = instancesPool;
		this.chunkSize = chunkSize;
		this.digestSize = digestSize;
	}

	reset() {
		this.buffered = 0;
		this.exports.init();
	}

	/**
	 * @param {Buffer | string} data data
	 * @param {BufferEncoding=} encoding encoding
	 * @returns {this} itself
	 */
	update(data, encoding) {
		if (typeof data === "string") {
			while (data.length > MAX_SHORT_STRING) {
				this._updateWithShortString(data.slice(0, MAX_SHORT_STRING), encoding);
				data = data.slice(MAX_SHORT_STRING);
			}
			this._updateWithShortString(data, encoding);
			return this;
		}
		this._updateWithBuffer(data);
		return this;
	}

	/**
	 * @param {string} data data
	 * @param {BufferEncoding=} encoding encoding
	 * @returns {void}
	 */
	_updateWithShortString(data, encoding) {
		const { exports, buffered, mem, chunkSize } = this;
		let endPos;
		if (data.length < 70) {
			if (!encoding || encoding === "utf-8" || encoding === "utf8") {
				endPos = buffered;
				for (let i = 0; i < data.length; i++) {
					const cc = data.charCodeAt(i);
					if (cc < 0x80) mem[endPos++] = cc;
					else if (cc < 0x800) {
						mem[endPos] = (cc >> 6) | 0xc0;
						mem[endPos + 1] = (cc & 0x3f) | 0x80;
						endPos += 2;
					} else {
						// bail-out for weird chars
						endPos += mem.write(data.slice(i), endPos, encoding);
						break;
					}
				}
			} else if (encoding === "latin1") {
				endPos = buffered;
				for (let i = 0; i < data.length; i++) {
					const cc = data.charCodeAt(i);
					mem[endPos++] = cc;
				}
			} else {
				endPos = buffered + mem.write(data, buffered, encoding);
			}
		} else {
			endPos = buffered + mem.write(data, buffered, encoding);
		}
		if (endPos < chunkSize) {
			this.buffered = endPos;
		} else {
			const l = endPos & ~(this.chunkSize - 1);
			exports.update(l);
			const newBuffered = endPos - l;
			this.buffered = newBuffered;
			if (newBuffered > 0) mem.copyWithin(0, l, endPos);
		}
	}

	/**
	 * @param {Buffer} data data
	 * @returns {void}
	 */
	_updateWithBuffer(data) {
		const { exports, buffered, mem } = this;
		const length = data.length;
		if (buffered + length < this.chunkSize) {
			data.copy(mem, buffered, 0, length);
			this.buffered += length;
		} else {
			const l = (buffered + length) & ~(this.chunkSize - 1);
			if (l > 65536) {
				let i = 65536 - buffered;
				data.copy(mem, buffered, 0, i);
				exports.update(65536);
				const stop = l - buffered - 65536;
				while (i < stop) {
					data.copy(mem, 0, i, i + 65536);
					exports.update(65536);
					i += 65536;
				}
				data.copy(mem, 0, i, l - buffered);
				exports.update(l - buffered - i);
			} else {
				data.copy(mem, buffered, 0, l - buffered);
				exports.update(l);
			}
			const newBuffered = length + buffered - l;
			this.buffered = newBuffered;
			if (newBuffered > 0) data.copy(mem, 0, length - newBuffered, length);
		}
	}

	digest(type) {
		const { exports, buffered, mem, digestSize } = this;
		exports.final(buffered);
		this.instancesPool.push(this);
		const hex = mem.toString("latin1", 0, digestSize);
		if (type === "hex") return hex;
		if (type === "binary" || !type) return Buffer.from(hex, "hex");
		return Buffer.from(hex, "hex").toString(type);
	}
}

const create = (wasmModule, instancesPool, chunkSize, digestSize) => {
	if (instancesPool.length > 0) {
		const old = instancesPool.pop();
		old.reset();
		return old;
	} else {
		return new WasmHash(
			new WebAssembly.Instance(wasmModule),
			instancesPool,
			chunkSize,
			digestSize
		);
	}
};

module.exports = create;
module.exports.MAX_SHORT_STRING = MAX_SHORT_STRING;


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

"use strict";

const path = require("path");

const WINDOWS_ABS_PATH_REGEXP = /^[a-zA-Z]:[\\/]/;
const SEGMENTS_SPLIT_REGEXP = /([|!])/;
const WINDOWS_PATH_SEPARATOR_REGEXP = /\\/g;

/**
 * @typedef {object} MakeRelativePathsCache
 * @property {Map<string, Map<string, string>>=} relativePaths
 */

/**
 * @param {string} relativePath relative path
 * @returns {string} request
 */
const relativePathToRequest = relativePath => {
	if (relativePath === "") return "./.";
	if (relativePath === "..") return "../.";
	if (relativePath.startsWith("../")) return relativePath;
	return `./${relativePath}`;
};

/**
 * @param {string} context context for relative path
 * @param {string} maybeAbsolutePath path to make relative
 * @returns {string} relative path in request style
 */
const absoluteToRequest = (context, maybeAbsolutePath) => {
	if (maybeAbsolutePath[0] === "/") {
		if (
			maybeAbsolutePath.length > 1 &&
			maybeAbsolutePath[maybeAbsolutePath.length - 1] === "/"
		) {
			// this 'path' is actually a regexp generated by dynamic requires.
			// Don't treat it as an absolute path.
			return maybeAbsolutePath;
		}

		const querySplitPos = maybeAbsolutePath.indexOf("?");
		let resource =
			querySplitPos === -1
				? maybeAbsolutePath
				: maybeAbsolutePath.slice(0, querySplitPos);
		resource = relativePathToRequest(path.posix.relative(context, resource));
		return querySplitPos === -1
			? resource
			: resource + maybeAbsolutePath.slice(querySplitPos);
	}

	if (WINDOWS_ABS_PATH_REGEXP.test(maybeAbsolutePath)) {
		const querySplitPos = maybeAbsolutePath.indexOf("?");
		let resource =
			querySplitPos === -1
				? maybeAbsolutePath
				: maybeAbsolutePath.slice(0, querySplitPos);
		resource = path.win32.relative(context, resource);
		if (!WINDOWS_ABS_PATH_REGEXP.test(resource)) {
			resource = relativePathToRequest(
				resource.replace(WINDOWS_PATH_SEPARATOR_REGEXP, "/")
			);
		}
		return querySplitPos === -1
			? resource
			: resource + maybeAbsolutePath.slice(querySplitPos);
	}

	// not an absolute path
	return maybeAbsolutePath;
};

/**
 * @param {string} context context for relative path
 * @param {string} relativePath path
 * @returns {string} absolute path
 */
const requestToAbsolute = (context, relativePath) => {
	if (relativePath.startsWith("./") || relativePath.startsWith("../"))
		return path.join(context, relativePath);
	return relativePath;
};

const makeCacheable = realFn => {
	/** @type {WeakMap<object, Map<string, ParsedResource>>} */
	const cache = new WeakMap();

	const getCache = associatedObjectForCache => {
		const entry = cache.get(associatedObjectForCache);
		if (entry !== undefined) return entry;
		/** @type {Map<string, ParsedResource>} */
		const map = new Map();
		cache.set(associatedObjectForCache, map);
		return map;
	};

	/**
	 * @param {string} str the path with query and fragment
	 * @param {object=} associatedObjectForCache an object to which the cache will be attached
	 * @returns {ParsedResource} parsed parts
	 */
	const fn = (str, associatedObjectForCache) => {
		if (!associatedObjectForCache) return realFn(str);
		const cache = getCache(associatedObjectForCache);
		const entry = cache.get(str);
		if (entry !== undefined) return entry;
		const result = realFn(str);
		cache.set(str, result);
		return result;
	};

	fn.bindCache = associatedObjectForCache => {
		const cache = getCache(associatedObjectForCache);
		return str => {
			const entry = cache.get(str);
			if (entry !== undefined) return entry;
			const result = realFn(str);
			cache.set(str, result);
			return result;
		};
	};

	return fn;
};

const makeCacheableWithContext = fn => {
	/** @type {WeakMap<object, Map<string, Map<string, string>>>} */
	const cache = new WeakMap();

	/**
	 * @param {string} context context used to create relative path
	 * @param {string} identifier identifier used to create relative path
	 * @param {object=} associatedObjectForCache an object to which the cache will be attached
	 * @returns {string} the returned relative path
	 */
	const cachedFn = (context, identifier, associatedObjectForCache) => {
		if (!associatedObjectForCache) return fn(context, identifier);

		let innerCache = cache.get(associatedObjectForCache);
		if (innerCache === undefined) {
			innerCache = new Map();
			cache.set(associatedObjectForCache, innerCache);
		}

		let cachedResult;
		let innerSubCache = innerCache.get(context);
		if (innerSubCache === undefined) {
			innerCache.set(context, (innerSubCache = new Map()));
		} else {
			cachedResult = innerSubCache.get(identifier);
		}

		if (cachedResult !== undefined) {
			return cachedResult;
		} else {
			const result = fn(context, identifier);
			innerSubCache.set(identifier, result);
			return result;
		}
	};

	/**
	 * @param {object=} associatedObjectForCache an object to which the cache will be attached
	 * @returns {function(string, string): string} cached function
	 */
	cachedFn.bindCache = associatedObjectForCache => {
		let innerCache;
		if (associatedObjectForCache) {
			innerCache = cache.get(associatedObjectForCache);
			if (innerCache === undefined) {
				innerCache = new Map();
				cache.set(associatedObjectForCache, innerCache);
			}
		} else {
			innerCache = new Map();
		}

		/**
		 * @param {string} context context used to create relative path
		 * @param {string} identifier identifier used to create relative path
		 * @returns {string} the returned relative path
		 */
		const boundFn = (context, identifier) => {
			let cachedResult;
			let innerSubCache = innerCache.get(context);
			if (innerSubCache === undefined) {
				innerCache.set(context, (innerSubCache = new Map()));
			} else {
				cachedResult = innerSubCache.get(identifier);
			}

			if (cachedResult !== undefined) {
				return cachedResult;
			} else {
				const result = fn(context, identifier);
				innerSubCache.set(identifier, result);
				return result;
			}
		};

		return boundFn;
	};

	/**
	 * @param {string} context context used to create relative path
	 * @param {object=} associatedObjectForCache an object to which the cache will be attached
	 * @returns {function(string): string} cached function
	 */
	cachedFn.bindContextCache = (context, associatedObjectForCache) => {
		let innerSubCache;
		if (associatedObjectForCache) {
			let innerCache = cache.get(associatedObjectForCache);
			if (innerCache === undefined) {
				innerCache = new Map();
				cache.set(associatedObjectForCache, innerCache);
			}

			innerSubCache = innerCache.get(context);
			if (innerSubCache === undefined) {
				innerCache.set(context, (innerSubCache = new Map()));
			}
		} else {
			innerSubCache = new Map();
		}

		/**
		 * @param {string} identifier identifier used to create relative path
		 * @returns {string} the returned relative path
		 */
		const boundFn = identifier => {
			const cachedResult = innerSubCache.get(identifier);
			if (cachedResult !== undefined) {
				return cachedResult;
			} else {
				const result = fn(context, identifier);
				innerSubCache.set(identifier, result);
				return result;
			}
		};

		return boundFn;
	};

	return cachedFn;
};

/**
 *
 * @param {string} context context for relative path
 * @param {string} identifier identifier for path
 * @returns {string} a converted relative path
 */
const _makePathsRelative = (context, identifier) => {
	return identifier
		.split(SEGMENTS_SPLIT_REGEXP)
		.map(str => absoluteToRequest(context, str))
		.join("");
};

exports.makePathsRelative = makeCacheableWithContext(_makePathsRelative);

/**
 *
 * @param {string} context context for relative path
 * @param {string} identifier identifier for path
 * @returns {string} a converted relative path
 */
const _makePathsAbsolute = (context, identifier) => {
	return identifier
		.split(SEGMENTS_SPLIT_REGEXP)
		.map(str => requestToAbsolute(context, str))
		.join("");
};

exports.makePathsAbsolute = makeCacheableWithContext(_makePathsAbsolute);

/**
 * @param {string} context absolute context path
 * @param {string} request any request string may containing absolute paths, query string, etc.
 * @returns {string} a new request string avoiding absolute paths when possible
 */
const _contextify = (context, request) => {
	return request
		.split("!")
		.map(r => absoluteToRequest(context, r))
		.join("!");
};

const contextify = makeCacheableWithContext(_contextify);
exports.contextify = contextify;

/**
 * @param {string} context absolute context path
 * @param {string} request any request string
 * @returns {string} a new request string using absolute paths when possible
 */
const _absolutify = (context, request) => {
	return request
		.split("!")
		.map(r => requestToAbsolute(context, r))
		.join("!");
};

const absolutify = makeCacheableWithContext(_absolutify);
exports.absolutify = absolutify;

const PATH_QUERY_FRAGMENT_REGEXP =
	/^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
const PATH_QUERY_REGEXP = /^((?:\0.|[^?\0])*)(\?.*)?$/;

/** @typedef {{ resource: string, path: string, query: string, fragment: string }} ParsedResource */
/** @typedef {{ resource: string, path: string, query: string }} ParsedResourceWithoutFragment */

/**
 * @param {string} str the path with query and fragment
 * @returns {ParsedResource} parsed parts
 */
const _parseResource = str => {
	const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
	return {
		resource: str,
		path: match[1].replace(/\0(.)/g, "$1"),
		query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
		fragment: match[3] || ""
	};
};
exports.parseResource = makeCacheable(_parseResource);

/**
 * Parse resource, skips fragment part
 * @param {string} str the path with query and fragment
 * @returns {ParsedResourceWithoutFragment} parsed parts
 */
const _parseResourceWithoutFragment = str => {
	const match = PATH_QUERY_REGEXP.exec(str);
	return {
		resource: str,
		path: match[1].replace(/\0(.)/g, "$1"),
		query: match[2] ? match[2].replace(/\0(.)/g, "$1") : ""
	};
};
exports.parseResourceWithoutFragment = makeCacheable(
	_parseResourceWithoutFragment
);

/**
 * @param {string} filename the filename which should be undone
 * @param {string} outputPath the output path that is restored (only relevant when filename contains "..")
 * @param {boolean} enforceRelative true returns ./ for empty paths
 * @returns {string} repeated ../ to leave the directory of the provided filename to be back on output dir
 */
exports.getUndoPath = (filename, outputPath, enforceRelative) => {
	let depth = -1;
	let append = "";
	outputPath = outputPath.replace(/[\\/]$/, "");
	for (const part of filename.split(/[/\\]+/)) {
		if (part === "..") {
			if (depth > -1) {
				depth--;
			} else {
				const i = outputPath.lastIndexOf("/");
				const j = outputPath.lastIndexOf("\\");
				const pos = i < 0 ? j : j < 0 ? i : Math.max(i, j);
				if (pos < 0) return outputPath + "/";
				append = outputPath.slice(pos + 1) + "/" + append;
				outputPath = outputPath.slice(0, pos);
			}
		} else if (part !== ".") {
			depth++;
		}
	}
	return depth > 0
		? `${"../".repeat(depth)}${append}`
		: enforceRelative
			? `./${append}`
			: append;
};


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

"use strict";

// We need to include a list of requires here
// to allow webpack to be bundled with only static requires
// We could use a dynamic require(`../${request}`) but this
// would include too many modules and not every tool is able
// to process this
module.exports = {
	AsyncDependenciesBlock: () => require("../AsyncDependenciesBlock"),
	CommentCompilationWarning: () => require("../CommentCompilationWarning"),
	ContextModule: () => require("../ContextModule"),
	"cache/PackFileCacheStrategy": () =>
		require("../cache/PackFileCacheStrategy"),
	"cache/ResolverCachePlugin": () => require("../cache/ResolverCachePlugin"),
	"container/ContainerEntryDependency": () =>
		require("../container/ContainerEntryDependency"),
	"container/ContainerEntryModule": () =>
		require("../container/ContainerEntryModule"),
	"container/ContainerExposedDependency": () =>
		require("../container/ContainerExposedDependency"),
	"container/FallbackDependency": () =>
		require("../container/FallbackDependency"),
	"container/FallbackItemDependency": () =>
		require("../container/FallbackItemDependency"),
	"container/FallbackModule": () => require("../container/FallbackModule"),
	"container/RemoteModule": () => require("../container/RemoteModule"),
	"container/RemoteToExternalDependency": () =>
		require("../container/RemoteToExternalDependency"),
	"dependencies/AMDDefineDependency": () =>
		require("../dependencies/AMDDefineDependency"),
	"dependencies/AMDRequireArrayDependency": () =>
		require("../dependencies/AMDRequireArrayDependency"),
	"dependencies/AMDRequireContextDependency": () =>
		require("../dependencies/AMDRequireContextDependency"),
	"dependencies/AMDRequireDependenciesBlock": () =>
		require("../dependencies/AMDRequireDependenciesBlock"),
	"dependencies/AMDRequireDependency": () =>
		require("../dependencies/AMDRequireDependency"),
	"dependencies/AMDRequireItemDependency": () =>
		require("../dependencies/AMDRequireItemDependency"),
	"dependencies/CachedConstDependency": () =>
		require("../dependencies/CachedConstDependency"),
	"dependencies/ExternalModuleDependency": () =>
		require("../dependencies/ExternalModuleDependency"),
	"dependencies/ExternalModuleInitFragment": () =>
		require("../dependencies/ExternalModuleInitFragment"),
	"dependencies/CreateScriptUrlDependency": () =>
		require("../dependencies/CreateScriptUrlDependency"),
	"dependencies/CommonJsRequireContextDependency": () =>
		require("../dependencies/CommonJsRequireContextDependency"),
	"dependencies/CommonJsExportRequireDependency": () =>
		require("../dependencies/CommonJsExportRequireDependency"),
	"dependencies/CommonJsExportsDependency": () =>
		require("../dependencies/CommonJsExportsDependency"),
	"dependencies/CommonJsFullRequireDependency": () =>
		require("../dependencies/CommonJsFullRequireDependency"),
	"dependencies/CommonJsRequireDependency": () =>
		require("../dependencies/CommonJsRequireDependency"),
	"dependencies/CommonJsSelfReferenceDependency": () =>
		require("../dependencies/CommonJsSelfReferenceDependency"),
	"dependencies/ConstDependency": () =>
		require("../dependencies/ConstDependency"),
	"dependencies/ContextDependency": () =>
		require("../dependencies/ContextDependency"),
	"dependencies/ContextElementDependency": () =>
		require("../dependencies/ContextElementDependency"),
	"dependencies/CriticalDependencyWarning": () =>
		require("../dependencies/CriticalDependencyWarning"),
	"dependencies/CssImportDependency": () =>
		require("../dependencies/CssImportDependency"),
	"dependencies/CssLocalIdentifierDependency": () =>
		require("../dependencies/CssLocalIdentifierDependency"),
	"dependencies/CssSelfLocalIdentifierDependency": () =>
		require("../dependencies/CssSelfLocalIdentifierDependency"),
	"dependencies/CssExportDependency": () =>
		require("../dependencies/CssExportDependency"),
	"dependencies/CssUrlDependency": () =>
		require("../dependencies/CssUrlDependency"),
	"dependencies/DelegatedSourceDependency": () =>
		require("../dependencies/DelegatedSourceDependency"),
	"dependencies/DllEntryDependency": () =>
		require("../dependencies/DllEntryDependency"),
	"dependencies/EntryDependency": () =>
		require("../dependencies/EntryDependency"),
	"dependencies/ExportsInfoDependency": () =>
		require("../dependencies/ExportsInfoDependency"),
	"dependencies/HarmonyAcceptDependency": () =>
		require("../dependencies/HarmonyAcceptDependency"),
	"dependencies/HarmonyAcceptImportDependency": () =>
		require("../dependencies/HarmonyAcceptImportDependency"),
	"dependencies/HarmonyCompatibilityDependency": () =>
		require("../dependencies/HarmonyCompatibilityDependency"),
	"dependencies/HarmonyExportExpressionDependency": () =>
		require("../dependencies/HarmonyExportExpressionDependency"),
	"dependencies/HarmonyExportHeaderDependency": () =>
		require("../dependencies/HarmonyExportHeaderDependency"),
	"dependencies/HarmonyExportImportedSpecifierDependency": () =>
		require("../dependencies/HarmonyExportImportedSpecifierDependency"),
	"dependencies/HarmonyExportSpecifierDependency": () =>
		require("../dependencies/HarmonyExportSpecifierDependency"),
	"dependencies/HarmonyImportSideEffectDependency": () =>
		require("../dependencies/HarmonyImportSideEffectDependency"),
	"dependencies/HarmonyImportSpecifierDependency": () =>
		require("../dependencies/HarmonyImportSpecifierDependency"),
	"dependencies/HarmonyEvaluatedImportSpecifierDependency": () =>
		require("../dependencies/HarmonyEvaluatedImportSpecifierDependency"),
	"dependencies/ImportContextDependency": () =>
		require("../dependencies/ImportContextDependency"),
	"dependencies/ImportDependency": () =>
		require("../dependencies/ImportDependency"),
	"dependencies/ImportEagerDependency": () =>
		require("../dependencies/ImportEagerDependency"),
	"dependencies/ImportWeakDependency": () =>
		require("../dependencies/ImportWeakDependency"),
	"dependencies/JsonExportsDependency": () =>
		require("../dependencies/JsonExportsDependency"),
	"dependencies/LocalModule": () => require("../dependencies/LocalModule"),
	"dependencies/LocalModuleDependency": () =>
		require("../dependencies/LocalModuleDependency"),
	"dependencies/ModuleDecoratorDependency": () =>
		require("../dependencies/ModuleDecoratorDependency"),
	"dependencies/ModuleHotAcceptDependency": () =>
		require("../dependencies/ModuleHotAcceptDependency"),
	"dependencies/ModuleHotDeclineDependency": () =>
		require("../dependencies/ModuleHotDeclineDependency"),
	"dependencies/ImportMetaHotAcceptDependency": () =>
		require("../dependencies/ImportMetaHotAcceptDependency"),
	"dependencies/ImportMetaHotDeclineDependency": () =>
		require("../dependencies/ImportMetaHotDeclineDependency"),
	"dependencies/ImportMetaContextDependency": () =>
		require("../dependencies/ImportMetaContextDependency"),
	"dependencies/ProvidedDependency": () =>
		require("../dependencies/ProvidedDependency"),
	"dependencies/PureExpressionDependency": () =>
		require("../dependencies/PureExpressionDependency"),
	"dependencies/RequireContextDependency": () =>
		require("../dependencies/RequireContextDependency"),
	"dependencies/RequireEnsureDependenciesBlock": () =>
		require("../dependencies/RequireEnsureDependenciesBlock"),
	"dependencies/RequireEnsureDependency": () =>
		require("../dependencies/RequireEnsureDependency"),
	"dependencies/RequireEnsureItemDependency": () =>
		require("../dependencies/RequireEnsureItemDependency"),
	"dependencies/RequireHeaderDependency": () =>
		require("../dependencies/RequireHeaderDependency"),
	"dependencies/RequireIncludeDependency": () =>
		require("../dependencies/RequireIncludeDependency"),
	"dependencies/RequireIncludeDependencyParserPlugin": () =>
		require("../dependencies/RequireIncludeDependencyParserPlugin"),
	"dependencies/RequireResolveContextDependency": () =>
		require("../dependencies/RequireResolveContextDependency"),
	"dependencies/RequireResolveDependency": () =>
		require("../dependencies/RequireResolveDependency"),
	"dependencies/RequireResolveHeaderDependency": () =>
		require("../dependencies/RequireResolveHeaderDependency"),
	"dependencies/RuntimeRequirementsDependency": () =>
		require("../dependencies/RuntimeRequirementsDependency"),
	"dependencies/StaticExportsDependency": () =>
		require("../dependencies/StaticExportsDependency"),
	"dependencies/SystemPlugin": () => require("../dependencies/SystemPlugin"),
	"dependencies/UnsupportedDependency": () =>
		require("../dependencies/UnsupportedDependency"),
	"dependencies/URLDependency": () => require("../dependencies/URLDependency"),
	"dependencies/WebAssemblyExportImportedDependency": () =>
		require("../dependencies/WebAssemblyExportImportedDependency"),
	"dependencies/WebAssemblyImportDependency": () =>
		require("../dependencies/WebAssemblyImportDependency"),
	"dependencies/WebpackIsIncludedDependency": () =>
		require("../dependencies/WebpackIsIncludedDependency"),
	"dependencies/WorkerDependency": () =>
		require("../dependencies/WorkerDependency"),
	"json/JsonData": () => require("../json/JsonData"),
	"optimize/ConcatenatedModule": () =>
		require("../optimize/ConcatenatedModule"),
	DelegatedModule: () => require("../DelegatedModule"),
	DependenciesBlock: () => require("../DependenciesBlock"),
	DllModule: () => require("../DllModule"),
	ExternalModule: () => require("../ExternalModule"),
	FileSystemInfo: () => require("../FileSystemInfo"),
	InitFragment: () => require("../InitFragment"),
	InvalidDependenciesModuleWarning: () =>
		require("../InvalidDependenciesModuleWarning"),
	Module: () => require("../Module"),
	ModuleBuildError: () => require("../ModuleBuildError"),
	ModuleDependencyWarning: () => require("../ModuleDependencyWarning"),
	ModuleError: () => require("../ModuleError"),
	ModuleGraph: () => require("../ModuleGraph"),
	ModuleParseError: () => require("../ModuleParseError"),
	ModuleWarning: () => require("../ModuleWarning"),
	NormalModule: () => require("../NormalModule"),
	CssModule: () => require("../CssModule"),
	RawDataUrlModule: () => require("../asset/RawDataUrlModule"),
	RawModule: () => require("../RawModule"),
	"sharing/ConsumeSharedModule": () =>
		require("../sharing/ConsumeSharedModule"),
	"sharing/ConsumeSharedFallbackDependency": () =>
		require("../sharing/ConsumeSharedFallbackDependency"),
	"sharing/ProvideSharedModule": () =>
		require("../sharing/ProvideSharedModule"),
	"sharing/ProvideSharedDependency": () =>
		require("../sharing/ProvideSharedDependency"),
	"sharing/ProvideForSharedDependency": () =>
		require("../sharing/ProvideForSharedDependency"),
	UnsupportedFeatureWarning: () => require("../UnsupportedFeatureWarning"),
	"util/LazySet": () => require("../util/LazySet"),
	UnhandledSchemeError: () => require("../UnhandledSchemeError"),
	NodeStuffInWebError: () => require("../NodeStuffInWebError"),
	EnvironmentNotSupportAsyncWarning: () =>
		require("../EnvironmentNotSupportAsyncWarning"),
	WebpackError: () => require("../WebpackError"),

	"util/registerExternalSerializer": () => {
		// already registered
	}
};


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

"use strict";

const { register } = require("./serialization");

/** @typedef {import("../serialization/ObjectMiddleware").Constructor} Constructor */

class ClassSerializer {
	constructor(Constructor) {
		this.Constructor = Constructor;
	}

	serialize(obj, context) {
		obj.serialize(context);
	}

	deserialize(context) {
		if (typeof this.Constructor.deserialize === "function") {
			return this.Constructor.deserialize(context);
		}
		const obj = new this.Constructor();
		obj.deserialize(context);
		return obj;
	}
}

/**
 * @param {Constructor} Constructor the constructor
 * @param {string} request the request which will be required when deserializing
 * @param {string | null} [name] the name to make multiple serializer unique when sharing a request
 */
module.exports = (Constructor, request, name = null) => {
	register(Constructor, request, name, new ClassSerializer(Constructor));
};


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

"use strict";

/** @template T @typedef {function(): T} FunctionReturning */

/**
 * @template T
 * @param {FunctionReturning<T>} fn memorized function
 * @returns {FunctionReturning<T>} new function
 */
const memoize = fn => {
	let cache = false;
	/** @type {T | undefined} */
	let result = undefined;
	return () => {
		if (cache) {
			return /** @type {T} */ (result);
		} else {
			result = fn();
			cache = true;
			// Allow to clean up memory for fn
			// and all dependent resources
			// eslint-disable-next-line no-warning-comments
			// @ts-ignore
			fn = undefined;
			return /** @type {T} */ (result);
		}
	};
};

module.exports = memoize;


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

"use strict";

/** @typedef {import("eslint-scope").Reference} Reference */
/** @typedef {import("eslint-scope").Variable} Variable */
/** @typedef {import("../javascript/JavascriptParser").AnyNode} AnyNode */
/** @typedef {import("../javascript/JavascriptParser").Program} Program */

/**
 * @param {Variable} variable variable
 * @returns {Reference[]} references
 */
const getAllReferences = variable => {
	let set = variable.references;
	// Look for inner scope variables too (like in class Foo { t() { Foo } })
	const identifiers = new Set(variable.identifiers);
	for (const scope of variable.scope.childScopes) {
		for (const innerVar of scope.variables) {
			if (innerVar.identifiers.some(id => identifiers.has(id))) {
				set = set.concat(innerVar.references);
				break;
			}
		}
	}
	return set;
};

/**
 * @param {Program | Program[]} ast ast
 * @param {AnyNode} node node
 * @returns {undefined | AnyNode[]} result
 */
const getPathInAst = (ast, node) => {
	if (ast === node) {
		return [];
	}

	const nr = node.range;

	const enterNode = n => {
		if (!n) return undefined;
		const r = n.range;
		if (r) {
			if (r[0] <= nr[0] && r[1] >= nr[1]) {
				const path = getPathInAst(n, node);
				if (path) {
					path.push(n);
					return path;
				}
			}
		}
		return undefined;
	};

	if (Array.isArray(ast)) {
		for (let i = 0; i < ast.length; i++) {
			const enterResult = enterNode(ast[i]);
			if (enterResult !== undefined) return enterResult;
		}
	} else if (ast && typeof ast === "object") {
		const keys = Object.keys(ast);
		for (let i = 0; i < keys.length; i++) {
			const value = ast[keys[i]];
			if (Array.isArray(value)) {
				const pathResult = getPathInAst(value, node);
				if (pathResult !== undefined) return pathResult;
			} else if (value && typeof value === "object") {
				const enterResult = enterNode(value);
				if (enterResult !== undefined) return enterResult;
			}
		}
	}
};

module.exports = { getAllReferences, getPathInAst };


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

"use strict";

const A_CODE = "a".charCodeAt(0);

/**
 * @param {string} hash hash
 * @param {number} hashLength hash length
 * @returns {string} returns hash that has at least one non numeric char
 */
module.exports = (hash, hashLength) => {
	if (hashLength < 1) return "";
	const slice = hash.slice(0, hashLength);
	if (slice.match(/[^\d]/)) return slice;
	return `${String.fromCharCode(
		A_CODE + (parseInt(hash[0], 10) % 6)
	)}${slice.slice(1)}`;
};


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

"use strict";

/**
 * Threshold for switching from 32-bit to 64-bit hashing. This is selected to ensure that the bias towards lower modulo results when using 32-bit hashing is <0.5%.
 * @type {number}
 */
const FNV_64_THRESHOLD = 1 << 24;

/**
 * The FNV-1a offset basis for 32-bit hash values.
 * @type {number}
 */
const FNV_OFFSET_32 = 2166136261;
/**
 * The FNV-1a prime for 32-bit hash values.
 * @type {number}
 */
const FNV_PRIME_32 = 16777619;
/**
 * The mask for a positive 32-bit signed integer.
 * @type {number}
 */
const MASK_31 = 0x7fffffff;

/**
 * The FNV-1a offset basis for 64-bit hash values.
 * @type {bigint}
 */
const FNV_OFFSET_64 = BigInt("0xCBF29CE484222325");
/**
 * The FNV-1a prime for 64-bit hash values.
 * @type {bigint}
 */
const FNV_PRIME_64 = BigInt("0x100000001B3");

/**
 * Computes a 32-bit FNV-1a hash value for the given string.
 * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
 * @param {string} str The input string to hash
 * @returns {number} - The computed hash value.
 */
function fnv1a32(str) {
	let hash = FNV_OFFSET_32;
	for (let i = 0, len = str.length; i < len; i++) {
		hash ^= str.charCodeAt(i);
		// Use Math.imul to do c-style 32-bit multiplication and keep only the 32 least significant bits
		hash = Math.imul(hash, FNV_PRIME_32);
	}
	// Force the result to be positive
	return hash & MASK_31;
}

/**
 * Computes a 64-bit FNV-1a hash value for the given string.
 * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
 * @param {string} str The input string to hash
 * @returns {bigint} - The computed hash value.
 */
function fnv1a64(str) {
	let hash = FNV_OFFSET_64;
	for (let i = 0, len = str.length; i < len; i++) {
		hash ^= BigInt(str.charCodeAt(i));
		hash = BigInt.asUintN(64, hash * FNV_PRIME_64);
	}
	return hash;
}

/**
 * Computes a hash value for the given string and range. This hashing algorithm is a modified
 * version of the [FNV-1a algorithm](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function).
 * It is optimized for speed and does **not** generate a cryptographic hash value.
 *
 * We use `numberHash` in `lib/ids/IdHelpers.js` to generate hash values for the module identifier. The generated
 * hash is used as a prefix for the module id's to avoid collisions with other modules.
 *
 * @param {string} str The input string to hash.
 * @param {number} range The range of the hash value (0 to range-1).
 * @returns {number} - The computed hash value.
 *
 * @example
 *
 * ```js
 * const numberHash = require("webpack/lib/util/numberHash");
 * numberHash("hello", 1000); // 73
 * numberHash("hello world"); // 72
 * ```
 *
 */
module.exports = (str, range) => {
	if (range < FNV_64_THRESHOLD) {
		return fnv1a32(str) % range;
	} else {
		return Number(fnv1a64(str) % BigInt(range));
	}
};


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

"use strict";

/**
 * Convert an object into an ES6 map
 *
 * @param {object} obj any object type that works with Object.entries()
 * @returns {Map<string, any>} an ES6 Map of KV pairs
 */
module.exports = function objectToMap(obj) {
	return new Map(Object.entries(obj));
};


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

"use strict";

/**
 * @template T
 * @template {Error} E
 * @param {Iterable<T>} items initial items
 * @param {number} concurrency number of items running in parallel
 * @param {function(T, function(T): void, function(E=): void): void} processor worker which pushes more items
 * @param {function(E=): void} callback all items processed
 * @returns {void}
 */
const processAsyncTree = (items, concurrency, processor, callback) => {
	const queue = Array.from(items);
	if (queue.length === 0) return callback();
	let processing = 0;
	let finished = false;
	let processScheduled = true;

	/**
	 * @param {T} item item
	 */
	const push = item => {
		queue.push(item);
		if (!processScheduled && processing < concurrency) {
			processScheduled = true;
			process.nextTick(processQueue);
		}
	};

	/**
	 * @param {E | null | undefined} err error
	 */
	const processorCallback = err => {
		processing--;
		if (err && !finished) {
			finished = true;
			callback(err);
			return;
		}
		if (!processScheduled) {
			processScheduled = true;
			process.nextTick(processQueue);
		}
	};

	const processQueue = () => {
		if (finished) return;
		while (processing < concurrency && queue.length > 0) {
			processing++;
			const item = /** @type {T} */ (queue.pop());
			processor(item, push, processorCallback);
		}
		processScheduled = false;
		if (queue.length === 0 && processing === 0 && !finished) {
			finished = true;
			callback();
		}
	};

	processQueue();
};

module.exports = processAsyncTree;


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

"use strict";

const {
	SAFE_IDENTIFIER,
	RESERVED_IDENTIFIER
} = require("../util/propertyName");

/**
 * @param {ArrayLike<string>} properties properties
 * @param {number} start start index
 * @returns {string} chain of property accesses
 */
const propertyAccess = (properties, start = 0) => {
	let str = "";
	for (let i = start; i < properties.length; i++) {
		const p = properties[i];
		if (`${+p}` === p) {
			str += `[${p}]`;
		} else if (SAFE_IDENTIFIER.test(p) && !RESERVED_IDENTIFIER.has(p)) {
			str += `.${p}`;
		} else {
			str += `[${JSON.stringify(p)}]`;
		}
	}
	return str;
};

module.exports = propertyAccess;


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

"use strict";

const SAFE_IDENTIFIER = /^[_a-zA-Z$][_a-zA-Z$0-9]*$/;
const RESERVED_IDENTIFIER = new Set([
	"break",
	"case",
	"catch",
	"class",
	"const",
	"continue",
	"debugger",
	"default",
	"delete",
	"do",
	"else",
	"export",
	"extends",
	"finally",
	"for",
	"function",
	"if",
	"import",
	"in",
	"instanceof",
	"new",
	"return",
	"super",
	"switch",
	"this",
	"throw",
	"try",
	"typeof",
	"var",
	"void",
	"while",
	"with",
	"enum",
	// strict mode
	"implements",
	"interface",
	"let",
	"package",
	"private",
	"protected",
	"public",
	"static",
	"yield",
	"yield",
	// module code
	"await",
	// skip future reserved keywords defined under ES1 till ES3
	// additional
	"null",
	"true",
	"false"
]);

/**
 * @summary Returns a valid JS property name for the given property.
 * Certain strings like "default", "null", and names with whitespace are not
 * valid JS property names, so they are returned as strings.
 *
 * @param {string} prop property name to analyze
 * @returns {string} valid JS property name
 */
const propertyName = prop => {
	if (SAFE_IDENTIFIER.test(prop) && !RESERVED_IDENTIFIER.has(prop)) {
		return prop;
	} else {
		return JSON.stringify(prop);
	}
};

module.exports = { SAFE_IDENTIFIER, RESERVED_IDENTIFIER, propertyName };


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

"use strict";

const { register } = require("./serialization");

const Position = /** @type {TODO} */ (require("acorn")).Position;
const SourceLocation = require("acorn").SourceLocation;
const ValidationError = require("schema-utils/dist/ValidationError").default;
const {
	CachedSource,
	ConcatSource,
	OriginalSource,
	PrefixSource,
	RawSource,
	ReplaceSource,
	SourceMapSource
} = require("webpack-sources");

/** @typedef {import("acorn").Position} Position */
/** @typedef {import("../Dependency").RealDependencyLocation} RealDependencyLocation */
/** @typedef {import("../Dependency").SourcePosition} SourcePosition */
/** @typedef {import("./serialization").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("./serialization").ObjectSerializerContext} ObjectSerializerContext */

/** @typedef {ObjectSerializerContext & { writeLazy?: (value: any) => void }} WebpackObjectSerializerContext */

const CURRENT_MODULE = "webpack/lib/util/registerExternalSerializer";

register(
	CachedSource,
	CURRENT_MODULE,
	"webpack-sources/CachedSource",
	new (class CachedSourceSerializer {
		/**
		 * @param {CachedSource} source the cached source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write, writeLazy }) {
			if (writeLazy) {
				writeLazy(source.originalLazy());
			} else {
				write(source.original());
			}
			write(source.getCachedData());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {CachedSource} cached source
		 */
		deserialize({ read }) {
			const source = read();
			const cachedData = read();
			return new CachedSource(source, cachedData);
		}
	})()
);

register(
	RawSource,
	CURRENT_MODULE,
	"webpack-sources/RawSource",
	new (class RawSourceSerializer {
		/**
		 * @param {RawSource} source the raw source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.buffer());
			write(!source.isBuffer());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {RawSource} raw source
		 */
		deserialize({ read }) {
			const source = read();
			const convertToString = read();
			return new RawSource(source, convertToString);
		}
	})()
);

register(
	ConcatSource,
	CURRENT_MODULE,
	"webpack-sources/ConcatSource",
	new (class ConcatSourceSerializer {
		/**
		 * @param {ConcatSource} source the concat source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.getChildren());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {ConcatSource} concat source
		 */
		deserialize({ read }) {
			const source = new ConcatSource();
			source.addAllSkipOptimizing(read());
			return source;
		}
	})()
);

register(
	PrefixSource,
	CURRENT_MODULE,
	"webpack-sources/PrefixSource",
	new (class PrefixSourceSerializer {
		/**
		 * @param {PrefixSource} source the prefix source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.getPrefix());
			write(source.original());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {PrefixSource} prefix source
		 */
		deserialize({ read }) {
			return new PrefixSource(read(), read());
		}
	})()
);

register(
	ReplaceSource,
	CURRENT_MODULE,
	"webpack-sources/ReplaceSource",
	new (class ReplaceSourceSerializer {
		/**
		 * @param {ReplaceSource} source the replace source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.original());
			write(source.getName());
			const replacements = source.getReplacements();
			write(replacements.length);
			for (const repl of replacements) {
				write(repl.start);
				write(repl.end);
			}
			for (const repl of replacements) {
				write(repl.content);
				write(repl.name);
			}
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {ReplaceSource} replace source
		 */
		deserialize({ read }) {
			const source = new ReplaceSource(read(), read());
			const len = read();
			const startEndBuffer = [];
			for (let i = 0; i < len; i++) {
				startEndBuffer.push(read(), read());
			}
			let j = 0;
			for (let i = 0; i < len; i++) {
				source.replace(
					startEndBuffer[j++],
					startEndBuffer[j++],
					read(),
					read()
				);
			}
			return source;
		}
	})()
);

register(
	OriginalSource,
	CURRENT_MODULE,
	"webpack-sources/OriginalSource",
	new (class OriginalSourceSerializer {
		/**
		 * @param {OriginalSource} source the original source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.buffer());
			write(source.getName());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {OriginalSource} original source
		 */
		deserialize({ read }) {
			const buffer = read();
			const name = read();
			return new OriginalSource(buffer, name);
		}
	})()
);

register(
	SourceLocation,
	CURRENT_MODULE,
	"acorn/SourceLocation",
	new (class SourceLocationSerializer {
		/**
		 * @param {SourceLocation} loc the location to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(loc, { write }) {
			write(loc.start.line);
			write(loc.start.column);
			write(loc.end.line);
			write(loc.end.column);
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {RealDependencyLocation} location
		 */
		deserialize({ read }) {
			return {
				start: {
					line: read(),
					column: read()
				},
				end: {
					line: read(),
					column: read()
				}
			};
		}
	})()
);

register(
	Position,
	CURRENT_MODULE,
	"acorn/Position",
	new (class PositionSerializer {
		/**
		 * @param {Position} pos the position to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(pos, { write }) {
			write(pos.line);
			write(pos.column);
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {SourcePosition} position
		 */
		deserialize({ read }) {
			return {
				line: read(),
				column: read()
			};
		}
	})()
);

register(
	SourceMapSource,
	CURRENT_MODULE,
	"webpack-sources/SourceMapSource",
	new (class SourceMapSourceSerializer {
		/**
		 * @param {SourceMapSource} source the source map source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(source, { write }) {
			write(source.getArgsAsBuffers());
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {SourceMapSource} source source map source
		 */
		deserialize({ read }) {
			// @ts-expect-error
			return new SourceMapSource(...read());
		}
	})()
);

register(
	ValidationError,
	CURRENT_MODULE,
	"schema-utils/ValidationError",
	new (class ValidationErrorSerializer {
		// TODO error should be ValidationError, but this fails the type checks
		/**
		 * @param {TODO} error the source map source to be serialized
		 * @param {WebpackObjectSerializerContext} context context
		 * @returns {void}
		 */
		serialize(error, { write }) {
			write(error.errors);
			write(error.schema);
			write({
				name: error.headerName,
				baseDataPath: error.baseDataPath,
				postFormatter: error.postFormatter
			});
		}

		/**
		 * @param {ObjectDeserializerContext} context context
		 * @returns {TODO} error
		 */
		deserialize({ read }) {
			return new ValidationError(read(), read(), read());
		}
	})()
);


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

"use strict";

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

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

/** @typedef {string | SortableSet<string> | undefined} RuntimeSpec */
/** @typedef {RuntimeSpec | boolean} RuntimeCondition */

/**
 * @param {Compilation} compilation the compilation
 * @param {string} name name of the entry
 * @param {EntryOptions=} options optionally already received entry options
 * @returns {RuntimeSpec} runtime
 */
exports.getEntryRuntime = (compilation, name, options) => {
	let dependOn;
	let runtime;
	if (options) {
		({ dependOn, runtime } = options);
	} else {
		const entry = compilation.entries.get(name);
		if (!entry) return name;
		({ dependOn, runtime } = entry.options);
	}
	if (dependOn) {
		/** @type {RuntimeSpec} */
		let result = undefined;
		const queue = new Set(dependOn);
		for (const name of queue) {
			const dep = compilation.entries.get(name);
			if (!dep) continue;
			const { dependOn, runtime } = dep.options;
			if (dependOn) {
				for (const name of dependOn) {
					queue.add(name);
				}
			} else {
				result = mergeRuntimeOwned(result, runtime || name);
			}
		}
		return result || name;
	} else {
		return runtime || name;
	}
};

/**
 * @param {RuntimeSpec} runtime runtime
 * @param {function(string | undefined): void} fn functor
 * @param {boolean} deterministicOrder enforce a deterministic order
 * @returns {void}
 */
const forEachRuntime = (runtime, fn, deterministicOrder = false) => {
	if (runtime === undefined) {
		fn(undefined);
	} else if (typeof runtime === "string") {
		fn(runtime);
	} else {
		if (deterministicOrder) runtime.sort();
		for (const r of runtime) {
			fn(r);
		}
	}
};
exports.forEachRuntime = forEachRuntime;

/**
 * @template T
 * @param {SortableSet<T>} set set
 * @returns {string} runtime key
 */
const getRuntimesKey = set => {
	set.sort();
	return Array.from(set).join("\n");
};

/**
 * @param {RuntimeSpec} runtime runtime(s)
 * @returns {string} key of runtimes
 */
const getRuntimeKey = runtime => {
	if (runtime === undefined) return "*";
	if (typeof runtime === "string") return runtime;
	return runtime.getFromUnorderedCache(getRuntimesKey);
};
exports.getRuntimeKey = getRuntimeKey;

/**
 * @param {string} key key of runtimes
 * @returns {RuntimeSpec} runtime(s)
 */
const keyToRuntime = key => {
	if (key === "*") return undefined;
	const items = key.split("\n");
	if (items.length === 1) return items[0];
	return new SortableSet(items);
};
exports.keyToRuntime = keyToRuntime;

/**
 * @template T
 * @param {SortableSet<T>} set set
 * @returns {string} runtime string
 */
const getRuntimesString = set => {
	set.sort();
	return Array.from(set).join("+");
};

/**
 * @param {RuntimeSpec} runtime runtime(s)
 * @returns {string} readable version
 */
const runtimeToString = runtime => {
	if (runtime === undefined) return "*";
	if (typeof runtime === "string") return runtime;
	return runtime.getFromUnorderedCache(getRuntimesString);
};
exports.runtimeToString = runtimeToString;

/**
 * @param {RuntimeCondition} runtimeCondition runtime condition
 * @returns {string} readable version
 */
exports.runtimeConditionToString = runtimeCondition => {
	if (runtimeCondition === true) return "true";
	if (runtimeCondition === false) return "false";
	return runtimeToString(runtimeCondition);
};

/**
 * @param {RuntimeSpec} a first
 * @param {RuntimeSpec} b second
 * @returns {boolean} true, when they are equal
 */
const runtimeEqual = (a, b) => {
	if (a === b) {
		return true;
	} else if (
		a === undefined ||
		b === undefined ||
		typeof a === "string" ||
		typeof b === "string"
	) {
		return false;
	} else if (a.size !== b.size) {
		return false;
	} else {
		a.sort();
		b.sort();
		const aIt = a[Symbol.iterator]();
		const bIt = b[Symbol.iterator]();
		for (;;) {
			const aV = aIt.next();
			if (aV.done) return true;
			const bV = bIt.next();
			if (aV.value !== bV.value) return false;
		}
	}
};
exports.runtimeEqual = runtimeEqual;

/**
 * @param {RuntimeSpec} a first
 * @param {RuntimeSpec} b second
 * @returns {-1|0|1} compare
 */
exports.compareRuntime = (a, b) => {
	if (a === b) {
		return 0;
	} else if (a === undefined) {
		return -1;
	} else if (b === undefined) {
		return 1;
	} else {
		const aKey = getRuntimeKey(a);
		const bKey = getRuntimeKey(b);
		if (aKey < bKey) return -1;
		if (aKey > bKey) return 1;
		return 0;
	}
};

/**
 * @param {RuntimeSpec} a first
 * @param {RuntimeSpec} b second
 * @returns {RuntimeSpec} merged
 */
const mergeRuntime = (a, b) => {
	if (a === undefined) {
		return b;
	} else if (b === undefined) {
		return a;
	} else if (a === b) {
		return a;
	} else if (typeof a === "string") {
		if (typeof b === "string") {
			const set = new SortableSet();
			set.add(a);
			set.add(b);
			return set;
		} else if (b.has(a)) {
			return b;
		} else {
			const set = new SortableSet(b);
			set.add(a);
			return set;
		}
	} else {
		if (typeof b === "string") {
			if (a.has(b)) return a;
			const set = new SortableSet(a);
			set.add(b);
			return set;
		} else {
			const set = new SortableSet(a);
			for (const item of b) set.add(item);
			if (set.size === a.size) return a;
			return set;
		}
	}
};
exports.mergeRuntime = mergeRuntime;

/**
 * @param {RuntimeCondition} a first
 * @param {RuntimeCondition} b second
 * @param {RuntimeSpec} runtime full runtime
 * @returns {RuntimeCondition} result
 */
exports.mergeRuntimeCondition = (a, b, runtime) => {
	if (a === false) return b;
	if (b === false) return a;
	if (a === true || b === true) return true;
	const merged = mergeRuntime(a, b);
	if (merged === undefined) return undefined;
	if (typeof merged === "string") {
		if (typeof runtime === "string" && merged === runtime) return true;
		return merged;
	}
	if (typeof runtime === "string" || runtime === undefined) return merged;
	if (merged.size === runtime.size) return true;
	return merged;
};

/**
 * @param {RuntimeSpec | true} a first
 * @param {RuntimeSpec | true} b second
 * @param {RuntimeSpec} runtime full runtime
 * @returns {RuntimeSpec | true} result
 */
exports.mergeRuntimeConditionNonFalse = (a, b, runtime) => {
	if (a === true || b === true) return true;
	const merged = mergeRuntime(a, b);
	if (merged === undefined) return undefined;
	if (typeof merged === "string") {
		if (typeof runtime === "string" && merged === runtime) return true;
		return merged;
	}
	if (typeof runtime === "string" || runtime === undefined) return merged;
	if (merged.size === runtime.size) return true;
	return merged;
};

/**
 * @param {RuntimeSpec} a first (may be modified)
 * @param {RuntimeSpec} b second
 * @returns {RuntimeSpec} merged
 */
const mergeRuntimeOwned = (a, b) => {
	if (b === undefined) {
		return a;
	} else if (a === b) {
		return a;
	} else if (a === undefined) {
		if (typeof b === "string") {
			return b;
		} else {
			return new SortableSet(b);
		}
	} else if (typeof a === "string") {
		if (typeof b === "string") {
			const set = new SortableSet();
			set.add(a);
			set.add(b);
			return set;
		} else {
			const set = new SortableSet(b);
			set.add(a);
			return set;
		}
	} else {
		if (typeof b === "string") {
			a.add(b);
			return a;
		} else {
			for (const item of b) a.add(item);
			return a;
		}
	}
};
exports.mergeRuntimeOwned = mergeRuntimeOwned;

/**
 * @param {RuntimeSpec} a first
 * @param {RuntimeSpec} b second
 * @returns {RuntimeSpec} merged
 */
exports.intersectRuntime = (a, b) => {
	if (a === undefined) {
		return b;
	} else if (b === undefined) {
		return a;
	} else if (a === b) {
		return a;
	} else if (typeof a === "string") {
		if (typeof b === "string") {
			return undefined;
		} else if (b.has(a)) {
			return a;
		} else {
			return undefined;
		}
	} else {
		if (typeof b === "string") {
			if (a.has(b)) return b;
			return undefined;
		} else {
			const set = new SortableSet();
			for (const item of b) {
				if (a.has(item)) set.add(item);
			}
			if (set.size === 0) return undefined;
			if (set.size === 1) for (const item of set) return item;
			return set;
		}
	}
};

/**
 * @param {RuntimeSpec} a first
 * @param {RuntimeSpec} b second
 * @returns {RuntimeSpec} result
 */
const subtractRuntime = (a, b) => {
	if (a === undefined) {
		return undefined;
	} else if (b === undefined) {
		return a;
	} else if (a === b) {
		return undefined;
	} else if (typeof a === "string") {
		if (typeof b === "string") {
			return a;
		} else if (b.has(a)) {
			return undefined;
		} else {
			return a;
		}
	} else {
		if (typeof b === "string") {
			if (!a.has(b)) return a;
			if (a.size === 2) {
				for (const item of a) {
					if (item !== b) return item;
				}
			}
			const set = new SortableSet(a);
			set.delete(b);
			return set;
		} else {
			const set = new SortableSet();
			for (const item of a) {
				if (!b.has(item)) set.add(item);
			}
			if (set.size === 0) return undefined;
			if (set.size === 1) for (const item of set) return item;
			return set;
		}
	}
};
exports.subtractRuntime = subtractRuntime;

/**
 * @param {RuntimeCondition} a first
 * @param {RuntimeCondition} b second
 * @param {RuntimeSpec} runtime runtime
 * @returns {RuntimeCondition} result
 */
exports.subtractRuntimeCondition = (a, b, runtime) => {
	if (b === true) return false;
	if (b === false) return a;
	if (a === false) return false;
	const result = subtractRuntime(a === true ? runtime : a, b);
	return result === undefined ? false : result;
};

/**
 * @param {RuntimeSpec} runtime runtime
 * @param {function(RuntimeSpec): boolean} filter filter function
 * @returns {boolean | RuntimeSpec} true/false if filter is constant for all runtimes, otherwise runtimes that are active
 */
exports.filterRuntime = (runtime, filter) => {
	if (runtime === undefined) return filter(undefined);
	if (typeof runtime === "string") return filter(runtime);
	let some = false;
	let every = true;
	let result = undefined;
	for (const r of runtime) {
		const v = filter(r);
		if (v) {
			some = true;
			result = mergeRuntimeOwned(result, r);
		} else {
			every = false;
		}
	}
	if (!some) return false;
	if (every) return true;
	return result;
};

/**
 * @template T
 * @typedef {Map<string, T>} RuntimeSpecMapInnerMap
 */

/**
 * @template T
 */
class RuntimeSpecMap {
	/**
	 * @param {RuntimeSpecMap<T>=} clone copy form this
	 */
	constructor(clone) {
		this._mode = clone ? clone._mode : 0; // 0 = empty, 1 = single entry, 2 = map
		/** @type {RuntimeSpec} */
		this._singleRuntime = clone ? clone._singleRuntime : undefined;
		/** @type {T | undefined} */
		this._singleValue = clone ? clone._singleValue : undefined;
		/** @type {RuntimeSpecMapInnerMap<T> | undefined} */
		this._map = clone && clone._map ? new Map(clone._map) : undefined;
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 * @returns {T | undefined} value
	 */
	get(runtime) {
		switch (this._mode) {
			case 0:
				return undefined;
			case 1:
				return runtimeEqual(this._singleRuntime, runtime)
					? this._singleValue
					: undefined;
			default:
				return /** @type {RuntimeSpecMapInnerMap<T>} */ (this._map).get(
					getRuntimeKey(runtime)
				);
		}
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 * @returns {boolean} true, when the runtime is stored
	 */
	has(runtime) {
		switch (this._mode) {
			case 0:
				return false;
			case 1:
				return runtimeEqual(this._singleRuntime, runtime);
			default:
				return /** @type {RuntimeSpecMapInnerMap<T>} */ (this._map).has(
					getRuntimeKey(runtime)
				);
		}
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 * @param {T} value the value
	 */
	set(runtime, value) {
		switch (this._mode) {
			case 0:
				this._mode = 1;
				this._singleRuntime = runtime;
				this._singleValue = value;
				break;
			case 1:
				if (runtimeEqual(this._singleRuntime, runtime)) {
					this._singleValue = value;
					break;
				}
				this._mode = 2;
				this._map = new Map();
				this._map.set(
					getRuntimeKey(this._singleRuntime),
					/** @type {T} */ (this._singleValue)
				);
				this._singleRuntime = undefined;
				this._singleValue = undefined;
			/* falls through */
			default:
				/** @type {RuntimeSpecMapInnerMap<T>} */
				(this._map).set(getRuntimeKey(runtime), value);
		}
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 * @param {() => TODO} computer function to compute the value
	 * @returns {TODO} true, when the runtime was deleted
	 */
	provide(runtime, computer) {
		switch (this._mode) {
			case 0:
				this._mode = 1;
				this._singleRuntime = runtime;
				return (this._singleValue = computer());
			case 1: {
				if (runtimeEqual(this._singleRuntime, runtime)) {
					return /** @type {T} */ (this._singleValue);
				}
				this._mode = 2;
				this._map = new Map();
				this._map.set(
					getRuntimeKey(this._singleRuntime),
					/** @type {T} */ (this._singleValue)
				);
				this._singleRuntime = undefined;
				this._singleValue = undefined;
				const newValue = computer();
				this._map.set(getRuntimeKey(runtime), newValue);
				return newValue;
			}
			default: {
				const key = getRuntimeKey(runtime);
				const value = /** @type {Map<string, T>} */ (this._map).get(key);
				if (value !== undefined) return value;
				const newValue = computer();
				/** @type {Map<string, T>} */
				(this._map).set(key, newValue);
				return newValue;
			}
		}
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 */
	delete(runtime) {
		switch (this._mode) {
			case 0:
				return;
			case 1:
				if (runtimeEqual(this._singleRuntime, runtime)) {
					this._mode = 0;
					this._singleRuntime = undefined;
					this._singleValue = undefined;
				}
				return;
			default:
				/** @type {RuntimeSpecMapInnerMap<T>} */
				(this._map).delete(getRuntimeKey(runtime));
		}
	}

	/**
	 * @param {RuntimeSpec} runtime the runtimes
	 * @param {function(T | undefined): T} fn function to update the value
	 */
	update(runtime, fn) {
		switch (this._mode) {
			case 0:
				throw new Error("runtime passed to update must exist");
			case 1: {
				if (runtimeEqual(this._singleRuntime, runtime)) {
					this._singleValue = fn(this._singleValue);
					break;
				}
				const newValue = fn(undefined);
				if (newValue !== undefined) {
					this._mode = 2;
					this._map = new Map();
					this._map.set(
						getRuntimeKey(this._singleRuntime),
						/** @type {T} */ (this._singleValue)
					);
					this._singleRuntime = undefined;
					this._singleValue = undefined;
					this._map.set(getRuntimeKey(runtime), newValue);
				}
				break;
			}
			default: {
				const key = getRuntimeKey(runtime);
				const oldValue = /** @type {Map<string, T>} */ (this._map).get(key);
				const newValue = fn(oldValue);
				if (newValue !== oldValue)
					/** @type {RuntimeSpecMapInnerMap<T>} */
					(this._map).set(key, newValue);
			}
		}
	}

	keys() {
		switch (this._mode) {
			case 0:
				return [];
			case 1:
				return [this._singleRuntime];
			default:
				return Array.from(
					/** @type {RuntimeSpecMapInnerMap<T>} */
					(this._map).keys(),
					keyToRuntime
				);
		}
	}

	values() {
		switch (this._mode) {
			case 0:
				return [][Symbol.iterator]();
			case 1:
				return [/** @type {T} */ (this._singleValue)][Symbol.iterator]();
			default:
				return /** @type {Map<string, T>} */ (this._map).values();
		}
	}

	get size() {
		if (/** @type {number} */ (this._mode) <= 1) return this._mode;
		return /** @type {Map<string, T>} */ (this._map).size;
	}
}

exports.RuntimeSpecMap = RuntimeSpecMap;

class RuntimeSpecSet {
	/**
	 * @param {Iterable<RuntimeSpec>=} iterable iterable
	 */
	constructor(iterable) {
		/** @type {Map<string, RuntimeSpec>} */
		this._map = new Map();
		if (iterable) {
			for (const item of iterable) {
				this.add(item);
			}
		}
	}

	/**
	 * @param {RuntimeSpec} runtime runtime
	 */
	add(runtime) {
		this._map.set(getRuntimeKey(runtime), runtime);
	}

	/**
	 * @param {RuntimeSpec} runtime runtime
	 * @returns {boolean} true, when the runtime exists
	 */
	has(runtime) {
		return this._map.has(getRuntimeKey(runtime));
	}

	[Symbol.iterator]() {
		return this._map.values();
	}

	get size() {
		return this._map.size;
	}
}

exports.RuntimeSpecSet = RuntimeSpecSet;