| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-28 00:09:48 +08:00
										 |  |  | const { compareRuntime } = require("./runtime"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** @typedef {import("../Chunk")} Chunk */ | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | /** @typedef {import("../Chunk").ChunkId} ChunkId */ | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | /** @typedef {import("../ChunkGraph")} ChunkGraph */ | 
					
						
							| 
									
										
										
										
											2019-09-26 21:51:40 +08:00
										 |  |  | /** @typedef {import("../ChunkGroup")} ChunkGroup */ | 
					
						
							| 
									
										
										
										
											2018-12-20 15:51:54 +08:00
										 |  |  | /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */ | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | /** @typedef {import("../ModuleGraph")} ModuleGraph */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @template T @typedef {function(T, T): -1|0|1} Comparator */ | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @template TArg @template T @typedef {function(TArg, T, T): -1|0|1} RawParameterizedComparator */ | 
					
						
							|  |  |  | /** @template TArg @template T @typedef {function(TArg): Comparator<T>} ParameterizedComparator */ | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  |  * @param {RawParameterizedComparator<any, T>} fn comparator with argument | 
					
						
							|  |  |  |  * @returns {ParameterizedComparator<any, T>} comparator | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | const createCachedParameterizedComparator = fn => { | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | 	/** @type {WeakMap<object, Comparator<T>>} */ | 
					
						
							|  |  |  | 	const map = new WeakMap(); | 
					
						
							|  |  |  | 	return arg => { | 
					
						
							|  |  |  | 		const cachedResult = map.get(arg); | 
					
						
							|  |  |  | 		if (cachedResult !== undefined) return cachedResult; | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * @param {T} a first item | 
					
						
							|  |  |  | 		 * @param {T} b second item | 
					
						
							|  |  |  | 		 * @returns {-1|0|1} compare result | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2021-04-20 21:17:54 +08:00
										 |  |  | 		const result = fn.bind(null, arg); | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | 		map.set(arg, result); | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {Chunk} a chunk | 
					
						
							|  |  |  |  * @param {Chunk} b chunk | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | exports.compareChunksById = (a, b) => { | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 	return compareIds( | 
					
						
							|  |  |  | 		/** @type {ChunkId} */ (a.id), | 
					
						
							|  |  |  | 		/** @type {ChunkId} */ (b.id) | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {Module} a module | 
					
						
							|  |  |  |  * @param {Module} b module | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | exports.compareModulesByIdentifier = (a, b) => { | 
					
						
							|  |  |  | 	return compareIds(a.identifier(), b.identifier()); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGraph} chunkGraph the chunk graph | 
					
						
							|  |  |  |  * @param {Module} a module | 
					
						
							|  |  |  |  * @param {Module} b module | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareModulesById = (chunkGraph, a, b) => { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:56:48 +08:00
										 |  |  | 	return compareIds(chunkGraph.getModuleId(a), chunkGraph.getModuleId(b)); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @type {ParameterizedComparator<ChunkGraph, Module>} */ | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | exports.compareModulesById = | 
					
						
							|  |  |  | 	createCachedParameterizedComparator(compareModulesById); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {number} a number | 
					
						
							|  |  |  |  * @param {number} b number | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareNumbers = (a, b) => { | 
					
						
							|  |  |  | 	if (typeof a !== typeof b) { | 
					
						
							|  |  |  | 		return typeof a < typeof b ? -1 : 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (a < b) return -1; | 
					
						
							|  |  |  | 	if (a > b) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | exports.compareNumbers = compareNumbers; | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 20:11:48 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} a string | 
					
						
							|  |  |  |  * @param {string} b string | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareStringsNumeric = (a, b) => { | 
					
						
							| 
									
										
										
										
											2024-01-30 08:45:02 +08:00
										 |  |  | 	const aLength = a.length; | 
					
						
							|  |  |  | 	const bLength = b.length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	let aChar = 0; | 
					
						
							|  |  |  | 	let bChar = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	let aIsDigit = false; | 
					
						
							|  |  |  | 	let bIsDigit = false; | 
					
						
							|  |  |  | 	let i = 0; | 
					
						
							|  |  |  | 	let j = 0; | 
					
						
							|  |  |  | 	while (i < aLength && j < bLength) { | 
					
						
							|  |  |  | 		aChar = a.charCodeAt(i); | 
					
						
							|  |  |  | 		bChar = b.charCodeAt(j); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		aIsDigit = aChar >= 48 && aChar <= 57; | 
					
						
							|  |  |  | 		bIsDigit = bChar >= 48 && bChar <= 57; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!aIsDigit && !bIsDigit) { | 
					
						
							|  |  |  | 			if (aChar < bChar) return -1; | 
					
						
							|  |  |  | 			if (aChar > bChar) return 1; | 
					
						
							|  |  |  | 			i++; | 
					
						
							|  |  |  | 			j++; | 
					
						
							|  |  |  | 		} else if (aIsDigit && !bIsDigit) { | 
					
						
							|  |  |  | 			// This segment of a is shorter than in b
 | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} else if (!aIsDigit && bIsDigit) { | 
					
						
							|  |  |  | 			// This segment of b is shorter than in a
 | 
					
						
							|  |  |  | 			return -1; | 
					
						
							| 
									
										
										
										
											2018-09-07 20:11:48 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2024-01-30 08:45:02 +08:00
										 |  |  | 			let aNumber = aChar - 48; | 
					
						
							|  |  |  | 			let bNumber = bChar - 48; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			while (++i < aLength) { | 
					
						
							|  |  |  | 				aChar = a.charCodeAt(i); | 
					
						
							|  |  |  | 				if (aChar < 48 || aChar > 57) break; | 
					
						
							|  |  |  | 				aNumber = aNumber * 10 + aChar - 48; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			while (++j < bLength) { | 
					
						
							|  |  |  | 				bChar = b.charCodeAt(j); | 
					
						
							|  |  |  | 				if (bChar < 48 || bChar > 57) break; | 
					
						
							|  |  |  | 				bNumber = bNumber * 10 + bChar - 48; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (aNumber < bNumber) return -1; | 
					
						
							|  |  |  | 			if (aNumber > bNumber) return 1; | 
					
						
							| 
									
										
										
										
											2018-09-07 20:11:48 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-01-30 08:45:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (j < bLength) { | 
					
						
							|  |  |  | 		// a is shorter than b
 | 
					
						
							|  |  |  | 		bChar = b.charCodeAt(j); | 
					
						
							|  |  |  | 		bIsDigit = bChar >= 48 && bChar <= 57; | 
					
						
							|  |  |  | 		return bIsDigit ? -1 : 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (i < aLength) { | 
					
						
							|  |  |  | 		// b is shorter than a
 | 
					
						
							|  |  |  | 		aChar = a.charCodeAt(i); | 
					
						
							|  |  |  | 		aIsDigit = aChar >= 48 && aChar <= 57; | 
					
						
							|  |  |  | 		return aIsDigit ? 1 : -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-07 20:11:48 +08:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | exports.compareStringsNumeric = compareStringsNumeric; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  |  * @param {ModuleGraph} moduleGraph the module graph | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  |  * @param {Module} a module | 
					
						
							|  |  |  |  * @param {Module} b module | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-09-04 15:04:05 +08:00
										 |  |  | const compareModulesByPostOrderIndexOrIdentifier = (moduleGraph, a, b) => { | 
					
						
							| 
									
										
										
										
											2018-09-04 01:23:27 +08:00
										 |  |  | 	const cmp = compareNumbers( | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 		/** @type {number} */ (moduleGraph.getPostOrderIndex(a)), | 
					
						
							|  |  |  | 		/** @type {number} */ (moduleGraph.getPostOrderIndex(b)) | 
					
						
							| 
									
										
										
										
											2018-08-21 22:12:00 +08:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-09-04 01:23:27 +08:00
										 |  |  | 	if (cmp !== 0) return cmp; | 
					
						
							|  |  |  | 	return compareIds(a.identifier(), b.identifier()); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @type {ParameterizedComparator<ModuleGraph, Module>} */ | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | exports.compareModulesByPostOrderIndexOrIdentifier = | 
					
						
							|  |  |  | 	createCachedParameterizedComparator( | 
					
						
							|  |  |  | 		compareModulesByPostOrderIndexOrIdentifier | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {ModuleGraph} moduleGraph the module graph | 
					
						
							|  |  |  |  * @param {Module} a module | 
					
						
							|  |  |  |  * @param {Module} b module | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-09-04 15:04:05 +08:00
										 |  |  | const compareModulesByPreOrderIndexOrIdentifier = (moduleGraph, a, b) => { | 
					
						
							| 
									
										
										
										
											2018-09-04 01:23:27 +08:00
										 |  |  | 	const cmp = compareNumbers( | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 		/** @type {number} */ (moduleGraph.getPreOrderIndex(a)), | 
					
						
							|  |  |  | 		/** @type {number} */ (moduleGraph.getPreOrderIndex(b)) | 
					
						
							| 
									
										
										
										
											2018-08-21 22:12:00 +08:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-09-04 01:23:27 +08:00
										 |  |  | 	if (cmp !== 0) return cmp; | 
					
						
							|  |  |  | 	return compareIds(a.identifier(), b.identifier()); | 
					
						
							| 
									
										
										
										
											2018-08-16 22:11:20 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @type {ParameterizedComparator<ModuleGraph, Module>} */ | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | exports.compareModulesByPreOrderIndexOrIdentifier = | 
					
						
							|  |  |  | 	createCachedParameterizedComparator( | 
					
						
							|  |  |  | 		compareModulesByPreOrderIndexOrIdentifier | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGraph} chunkGraph the chunk graph | 
					
						
							|  |  |  |  * @param {Module} a module | 
					
						
							|  |  |  |  * @param {Module} b module | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareModulesByIdOrIdentifier = (chunkGraph, a, b) => { | 
					
						
							| 
									
										
										
										
											2018-09-04 01:23:27 +08:00
										 |  |  | 	const cmp = compareIds(chunkGraph.getModuleId(a), chunkGraph.getModuleId(b)); | 
					
						
							|  |  |  | 	if (cmp !== 0) return cmp; | 
					
						
							|  |  |  | 	return compareIds(a.identifier(), b.identifier()); | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @type {ParameterizedComparator<ChunkGraph, Module>} */ | 
					
						
							|  |  |  | exports.compareModulesByIdOrIdentifier = createCachedParameterizedComparator( | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 	compareModulesByIdOrIdentifier | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 21:07:28 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGraph} chunkGraph the chunk graph | 
					
						
							|  |  |  |  * @param {Chunk} a chunk | 
					
						
							|  |  |  |  * @param {Chunk} b chunk | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareChunks = (chunkGraph, a, b) => { | 
					
						
							|  |  |  | 	return chunkGraph.compareChunks(a, b); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2020-03-13 17:27:45 +08:00
										 |  |  | /** @type {ParameterizedComparator<ChunkGraph, Chunk>} */ | 
					
						
							|  |  |  | exports.compareChunks = createCachedParameterizedComparator(compareChunks); | 
					
						
							| 
									
										
										
										
											2018-08-28 21:07:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 17:18:22 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string|number} a first id | 
					
						
							|  |  |  |  * @param {string|number} b second id | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareIds = (a, b) => { | 
					
						
							|  |  |  | 	if (typeof a !== typeof b) { | 
					
						
							|  |  |  | 		return typeof a < typeof b ? -1 : 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (a < b) return -1; | 
					
						
							|  |  |  | 	if (a > b) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exports.compareIds = compareIds; | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 19:13:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} a first string | 
					
						
							|  |  |  |  * @param {string} b second string | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareStrings = (a, b) => { | 
					
						
							|  |  |  | 	if (a < b) return -1; | 
					
						
							|  |  |  | 	if (a > b) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exports.compareStrings = compareStrings; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-26 21:51:40 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGroup} a first chunk group | 
					
						
							|  |  |  |  * @param {ChunkGroup} b second chunk group | 
					
						
							|  |  |  |  * @returns {-1|0|1} compare result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const compareChunkGroupsByIndex = (a, b) => { | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 	return /** @type {number} */ (a.index) < /** @type {number} */ (b.index) | 
					
						
							|  |  |  | 		? -1 | 
					
						
							|  |  |  | 		: 1; | 
					
						
							| 
									
										
										
										
											2019-09-26 21:51:40 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exports.compareChunkGroupsByIndex = compareChunkGroupsByIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template K1 {Object} | 
					
						
							|  |  |  |  * @template K2 | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class TwoKeyWeakMap { | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 		/** @private @type {WeakMap<any, WeakMap<any, T | undefined>>} */ | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | 		this._map = new WeakMap(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K1} key1 first key | 
					
						
							|  |  |  | 	 * @param {K2} key2 second key | 
					
						
							|  |  |  | 	 * @returns {T | undefined} value | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	get(key1, key2) { | 
					
						
							|  |  |  | 		const childMap = this._map.get(key1); | 
					
						
							|  |  |  | 		if (childMap === undefined) { | 
					
						
							|  |  |  | 			return undefined; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return childMap.get(key2); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {K1} key1 first key | 
					
						
							|  |  |  | 	 * @param {K2} key2 second key | 
					
						
							|  |  |  | 	 * @param {T | undefined} value new value | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	set(key1, key2, value) { | 
					
						
							|  |  |  | 		let childMap = this._map.get(key1); | 
					
						
							|  |  |  | 		if (childMap === undefined) { | 
					
						
							|  |  |  | 			childMap = new WeakMap(); | 
					
						
							|  |  |  | 			this._map.set(key1, childMap); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		childMap.set(key2, value); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {TwoKeyWeakMap<Comparator<any>, Comparator<any>, Comparator<any>>}} */ | 
					
						
							|  |  |  | const concatComparatorsCache = new TwoKeyWeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @param {Comparator<T>} c1 comparator | 
					
						
							|  |  |  |  * @param {Comparator<T>} c2 comparator | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  |  * @param {Comparator<T>[]} cRest comparators | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  |  * @returns {Comparator<T>} comparator | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  | const concatComparators = (c1, c2, ...cRest) => { | 
					
						
							|  |  |  | 	if (cRest.length > 0) { | 
					
						
							|  |  |  | 		const [c3, ...cRest2] = cRest; | 
					
						
							|  |  |  | 		return concatComparators(c1, concatComparators(c2, c3, ...cRest2)); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | 	const cacheEntry = /** @type {Comparator<T>} */ ( | 
					
						
							|  |  |  | 		concatComparatorsCache.get(c1, c2) | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | 	if (cacheEntry !== undefined) return cacheEntry; | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {T} a first value | 
					
						
							|  |  |  | 	 * @param {T} b second value | 
					
						
							|  |  |  | 	 * @returns {-1|0|1} compare result | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	const result = (a, b) => { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 		const res = c1(a, b); | 
					
						
							|  |  |  | 		if (res !== 0) return res; | 
					
						
							|  |  |  | 		return c2(a, b); | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | 	concatComparatorsCache.set(c1, c2, result); | 
					
						
							|  |  |  | 	return result; | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  | exports.concatComparators = concatComparators; | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 23:15:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template A, B | 
					
						
							|  |  |  |  * @typedef {(input: A) => B | undefined | null} Selector | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | /** @type {TwoKeyWeakMap<Selector<any, any>, Comparator<any>, Comparator<any>>}} */ | 
					
						
							|  |  |  | const compareSelectCache = new TwoKeyWeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @template R | 
					
						
							|  |  |  |  * @param {Selector<T, R>} getter getter for value | 
					
						
							|  |  |  |  * @param {Comparator<R>} comparator comparator | 
					
						
							|  |  |  |  * @returns {Comparator<T>} comparator | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | const compareSelect = (getter, comparator) => { | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | 	const cacheEntry = compareSelectCache.get(getter, comparator); | 
					
						
							|  |  |  | 	if (cacheEntry !== undefined) return cacheEntry; | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {T} a first value | 
					
						
							|  |  |  | 	 * @param {T} b second value | 
					
						
							|  |  |  | 	 * @returns {-1|0|1} compare result | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	const result = (a, b) => { | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 		const aValue = getter(a); | 
					
						
							|  |  |  | 		const bValue = getter(b); | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | 		if (aValue !== undefined && aValue !== null) { | 
					
						
							|  |  |  | 			if (bValue !== undefined && bValue !== null) { | 
					
						
							|  |  |  | 				return comparator(aValue, bValue); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-09-05 20:22:10 +08:00
										 |  |  | 			if (bValue !== undefined && bValue !== null) { | 
					
						
							|  |  |  | 				return 1; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2018-08-28 18:30:33 +08:00
										 |  |  | 	compareSelectCache.set(getter, comparator, result); | 
					
						
							|  |  |  | 	return result; | 
					
						
							| 
									
										
										
										
											2018-08-28 17:50:33 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | exports.compareSelect = compareSelect; | 
					
						
							| 
									
										
										
										
											2018-08-28 21:07:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** @type {WeakMap<Comparator<any>, Comparator<Iterable<any>>>} */ | 
					
						
							|  |  |  | const compareIteratorsCache = new WeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @param {Comparator<T>} elementComparator comparator for elements | 
					
						
							|  |  |  |  * @returns {Comparator<Iterable<T>>} comparator for iterables of elements | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | const compareIterables = elementComparator => { | 
					
						
							| 
									
										
										
										
											2018-08-28 21:07:28 +08:00
										 |  |  | 	const cacheEntry = compareIteratorsCache.get(elementComparator); | 
					
						
							|  |  |  | 	if (cacheEntry !== undefined) return cacheEntry; | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Iterable<T>} a first value | 
					
						
							|  |  |  | 	 * @param {Iterable<T>} b second value | 
					
						
							|  |  |  | 	 * @returns {-1|0|1} compare result | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	const result = (a, b) => { | 
					
						
							|  |  |  | 		const aI = a[Symbol.iterator](); | 
					
						
							|  |  |  | 		const bI = b[Symbol.iterator](); | 
					
						
							|  |  |  | 		// eslint-disable-next-line no-constant-condition
 | 
					
						
							|  |  |  | 		while (true) { | 
					
						
							|  |  |  | 			const aItem = aI.next(); | 
					
						
							|  |  |  | 			const bItem = bI.next(); | 
					
						
							|  |  |  | 			if (aItem.done) { | 
					
						
							|  |  |  | 				return bItem.done ? 0 : -1; | 
					
						
							|  |  |  | 			} else if (bItem.done) { | 
					
						
							|  |  |  | 				return 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			const res = elementComparator(aItem.value, bItem.value); | 
					
						
							|  |  |  | 			if (res !== 0) return res; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	compareIteratorsCache.set(elementComparator, result); | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | exports.compareIterables = compareIterables; | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 15:22:11 +08:00
										 |  |  | // TODO this is no longer needed when minimum node.js version is >= 12
 | 
					
						
							|  |  |  | // since these versions ship with a stable sort function
 | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @param {Iterable<T>} iterable original ordered list | 
					
						
							|  |  |  |  * @returns {Comparator<T>} comparator | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | exports.keepOriginalOrder = iterable => { | 
					
						
							|  |  |  | 	/** @type {Map<T, number>} */ | 
					
						
							|  |  |  | 	const map = new Map(); | 
					
						
							|  |  |  | 	let i = 0; | 
					
						
							|  |  |  | 	for (const item of iterable) { | 
					
						
							|  |  |  | 		map.set(item, i++); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 	return (a, b) => | 
					
						
							|  |  |  | 		compareNumbers( | 
					
						
							|  |  |  | 			/** @type {number} */ (map.get(a)), | 
					
						
							|  |  |  | 			/** @type {number} */ (map.get(b)) | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2018-09-05 22:06:20 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {ChunkGraph} chunkGraph the chunk graph | 
					
						
							|  |  |  |  * @returns {Comparator<Chunk>} comparator | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | exports.compareChunksNatural = chunkGraph => { | 
					
						
							|  |  |  | 	const cmpFn = exports.compareModulesById(chunkGraph); | 
					
						
							|  |  |  | 	const cmpIterableFn = compareIterables(cmpFn); | 
					
						
							|  |  |  | 	return concatComparators( | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 		compareSelect( | 
					
						
							|  |  |  | 			chunk => /** @type {string|number} */ (chunk.name), | 
					
						
							|  |  |  | 			compareIds | 
					
						
							|  |  |  | 		), | 
					
						
							| 
									
										
										
										
											2020-07-28 00:09:48 +08:00
										 |  |  | 		compareSelect(chunk => chunk.runtime, compareRuntime), | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | 		compareSelect( | 
					
						
							|  |  |  | 			/** | 
					
						
							|  |  |  | 			 * @param {Chunk} chunk a chunk | 
					
						
							|  |  |  | 			 * @returns {Iterable<Module>} modules | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			chunk => chunkGraph.getOrderedChunkModulesIterable(chunk, cmpFn), | 
					
						
							|  |  |  | 			cmpIterableFn | 
					
						
							| 
									
										
										
										
											2020-07-28 00:09:48 +08:00
										 |  |  | 		) | 
					
						
							| 
									
										
										
										
											2018-10-17 21:30:17 +08:00
										 |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-12-20 15:51:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Compare two locations | 
					
						
							|  |  |  |  * @param {DependencyLocation} a A location node | 
					
						
							|  |  |  |  * @param {DependencyLocation} b A location node | 
					
						
							|  |  |  |  * @returns {-1|0|1} sorting comparator value | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | exports.compareLocations = (a, b) => { | 
					
						
							|  |  |  | 	let isObjectA = typeof a === "object" && a !== null; | 
					
						
							|  |  |  | 	let isObjectB = typeof b === "object" && b !== null; | 
					
						
							|  |  |  | 	if (!isObjectA || !isObjectB) { | 
					
						
							|  |  |  | 		if (isObjectA) return 1; | 
					
						
							|  |  |  | 		if (isObjectB) return -1; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-27 07:21:22 +08:00
										 |  |  | 	if ("start" in a) { | 
					
						
							|  |  |  | 		if ("start" in b) { | 
					
						
							|  |  |  | 			const ap = a.start; | 
					
						
							|  |  |  | 			const bp = b.start; | 
					
						
							|  |  |  | 			if (ap.line < bp.line) return -1; | 
					
						
							|  |  |  | 			if (ap.line > bp.line) return 1; | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 			if (/** @type {number} */ (ap.column) < /** @type {number} */ (bp.column)) | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 			if (/** @type {number} */ (ap.column) > /** @type {number} */ (bp.column)) | 
					
						
							|  |  |  | 				return 1; | 
					
						
							| 
									
										
										
										
											2021-04-27 07:21:22 +08:00
										 |  |  | 		} else return -1; | 
					
						
							|  |  |  | 	} else if ("start" in b) return 1; | 
					
						
							|  |  |  | 	if ("name" in a) { | 
					
						
							|  |  |  | 		if ("name" in b) { | 
					
						
							|  |  |  | 			if (a.name < b.name) return -1; | 
					
						
							|  |  |  | 			if (a.name > b.name) return 1; | 
					
						
							|  |  |  | 		} else return -1; | 
					
						
							|  |  |  | 	} else if ("name" in b) return 1; | 
					
						
							|  |  |  | 	if ("index" in a) { | 
					
						
							|  |  |  | 		if ("index" in b) { | 
					
						
							| 
									
										
										
										
											2024-02-22 22:20:17 +08:00
										 |  |  | 			if (/** @type {number} */ (a.index) < /** @type {number} */ (b.index)) | 
					
						
							|  |  |  | 				return -1; | 
					
						
							|  |  |  | 			if (/** @type {number} */ (a.index) > /** @type {number} */ (b.index)) | 
					
						
							|  |  |  | 				return 1; | 
					
						
							| 
									
										
										
										
											2021-04-27 07:21:22 +08:00
										 |  |  | 		} else return -1; | 
					
						
							|  |  |  | 	} else if ("index" in b) return 1; | 
					
						
							| 
									
										
										
										
											2018-12-20 15:51:54 +08:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | }; |