comparators.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { getFullModuleName } = require("../ids/IdHelpers");
  7. const { compareRuntime } = require("./runtime");
  8. /** @import Chunk, { ChunkName, ChunkId } from "../Chunk" */
  9. /** @import ChunkGraph, { ModuleId } from "../ChunkGraph" */
  10. /** @import ChunkGroup from "../ChunkGroup" */
  11. /** @import Compiler from "../Compiler" */
  12. /** @import Dependency, { DependencyLocation } from "../Dependency" */
  13. /** @import HarmonyImportSideEffectDependency from "../dependencies/HarmonyImportSideEffectDependency" */
  14. /** @import HarmonyImportSpecifierDependency from "../dependencies/HarmonyImportSpecifierDependency" */
  15. /** @import Module from "../Module" */
  16. /** @import ModuleGraph from "../ModuleGraph" */
  17. /** @import WebpackErrorType from "../errors/WebpackError" */
  18. /** @import ModuleDependency from "../dependencies/ModuleDependency" */
  19. /**
  20. * Defines the dependency source order type used by this module.
  21. * @typedef {object} DependencySourceOrder
  22. * @property {number} main the main source order
  23. * @property {number} sub the sub source order
  24. */
  25. /**
  26. * Defines the comparator type used by this module.
  27. * @template T
  28. * @typedef {(a: T, b: T) => -1 | 0 | 1} Comparator
  29. */
  30. /**
  31. * Defines the raw parameterized comparator type used by this module.
  32. * @template {object} TArg
  33. * @template T
  34. * @typedef {(tArg: TArg, a: T, b: T) => -1 | 0 | 1} RawParameterizedComparator
  35. */
  36. /**
  37. * Defines the parameterized comparator type used by this module.
  38. * @template {object} TArg
  39. * @template T
  40. * @typedef {(tArg: TArg) => Comparator<T>} ParameterizedComparator
  41. */
  42. /**
  43. * Creates a cached parameterized comparator.
  44. * @template {object} TArg
  45. * @template {object} T
  46. * @param {RawParameterizedComparator<TArg, T>} fn comparator with argument
  47. * @returns {ParameterizedComparator<TArg, T>} comparator
  48. */
  49. const createCachedParameterizedComparator = (fn) => {
  50. /** @type {WeakMap<TArg, Comparator<T>>} */
  51. const map = new WeakMap();
  52. return (arg) => {
  53. const cachedResult = map.get(arg);
  54. if (cachedResult !== undefined) return cachedResult;
  55. // arrow closure dispatches faster than a bound function on the sort hot path
  56. /**
  57. * @param {T} a first item
  58. * @param {T} b second item
  59. * @returns {-1 | 0 | 1} compare result
  60. */
  61. const result = (a, b) => fn(arg, a, b);
  62. map.set(arg, result);
  63. return result;
  64. };
  65. };
  66. /**
  67. * Compares the provided values and returns their ordering.
  68. * @param {string | number} a first id
  69. * @param {string | number} b second id
  70. * @returns {-1 | 0 | 1} compare result
  71. */
  72. const compareIds = (a, b) => {
  73. if (typeof a !== typeof b) {
  74. return typeof a < typeof b ? -1 : 1;
  75. }
  76. if (a < b) return -1;
  77. if (a > b) return 1;
  78. return 0;
  79. };
  80. /**
  81. * Compares iterables.
  82. * @template T
  83. * @param {Comparator<T>} elementComparator comparator for elements
  84. * @returns {Comparator<Iterable<T>>} comparator for iterables of elements
  85. */
  86. const compareIterables = (elementComparator) => {
  87. const cacheEntry = compareIteratorsCache.get(elementComparator);
  88. if (cacheEntry !== undefined) return cacheEntry;
  89. /**
  90. * Returns compare result.
  91. * @param {Iterable<T>} a first value
  92. * @param {Iterable<T>} b second value
  93. * @returns {-1 | 0 | 1} compare result
  94. */
  95. const result = (a, b) => {
  96. const aI = a[Symbol.iterator]();
  97. const bI = b[Symbol.iterator]();
  98. while (true) {
  99. const aItem = aI.next();
  100. const bItem = bI.next();
  101. if (aItem.done) {
  102. return bItem.done ? 0 : -1;
  103. } else if (bItem.done) {
  104. return 1;
  105. }
  106. const res = elementComparator(aItem.value, bItem.value);
  107. if (res !== 0) return res;
  108. }
  109. };
  110. compareIteratorsCache.set(elementComparator, result);
  111. return result;
  112. };
  113. /**
  114. * Compare two locations
  115. * @param {DependencyLocation} a A location node
  116. * @param {DependencyLocation} b A location node
  117. * @returns {-1 | 0 | 1} sorting comparator value
  118. */
  119. const compareLocations = (a, b) => {
  120. const isObjectA = typeof a === "object" && a !== null;
  121. const isObjectB = typeof b === "object" && b !== null;
  122. if (!isObjectA || !isObjectB) {
  123. if (isObjectA) return 1;
  124. if (isObjectB) return -1;
  125. return 0;
  126. }
  127. if ("start" in a) {
  128. if ("start" in b) {
  129. const ap = a.start;
  130. const bp = b.start;
  131. if (ap.line < bp.line) return -1;
  132. if (ap.line > bp.line) return 1;
  133. if (
  134. /** @type {number} */ (ap.column) < /** @type {number} */ (bp.column)
  135. ) {
  136. return -1;
  137. }
  138. if (
  139. /** @type {number} */ (ap.column) > /** @type {number} */ (bp.column)
  140. ) {
  141. return 1;
  142. }
  143. } else {
  144. return -1;
  145. }
  146. } else if ("start" in b) {
  147. return 1;
  148. }
  149. if ("name" in a) {
  150. if ("name" in b) {
  151. if (a.name < b.name) return -1;
  152. if (a.name > b.name) return 1;
  153. } else {
  154. return -1;
  155. }
  156. } else if ("name" in b) {
  157. return 1;
  158. }
  159. if ("index" in a) {
  160. if ("index" in b) {
  161. if (/** @type {number} */ (a.index) < /** @type {number} */ (b.index)) {
  162. return -1;
  163. }
  164. if (/** @type {number} */ (a.index) > /** @type {number} */ (b.index)) {
  165. return 1;
  166. }
  167. } else {
  168. return -1;
  169. }
  170. } else if ("index" in b) {
  171. return 1;
  172. }
  173. return 0;
  174. };
  175. /**
  176. * Compares modules by id.
  177. * @param {ChunkGraph} chunkGraph the chunk graph
  178. * @param {Module} a module
  179. * @param {Module} b module
  180. * @returns {-1 | 0 | 1} compare result
  181. */
  182. const compareModulesById = (chunkGraph, a, b) =>
  183. compareIds(
  184. /** @type {ModuleId} */ (chunkGraph.getModuleId(a)),
  185. /** @type {ModuleId} */ (chunkGraph.getModuleId(b))
  186. );
  187. /**
  188. * Compares the provided values and returns their ordering.
  189. * @param {number} a number
  190. * @param {number} b number
  191. * @returns {-1 | 0 | 1} compare result
  192. */
  193. const compareNumbers = (a, b) => {
  194. if (typeof a !== typeof b) {
  195. return typeof a < typeof b ? -1 : 1;
  196. }
  197. if (a < b) return -1;
  198. if (a > b) return 1;
  199. return 0;
  200. };
  201. /**
  202. * Compares strings numeric.
  203. * @param {string} a string
  204. * @param {string} b string
  205. * @returns {-1 | 0 | 1} compare result
  206. */
  207. const compareStringsNumeric = (a, b) => {
  208. const aLength = a.length;
  209. const bLength = b.length;
  210. let aChar = 0;
  211. let bChar = 0;
  212. let aIsDigit = false;
  213. let bIsDigit = false;
  214. let i = 0;
  215. let j = 0;
  216. while (i < aLength && j < bLength) {
  217. aChar = a.charCodeAt(i);
  218. bChar = b.charCodeAt(j);
  219. aIsDigit = aChar >= 48 && aChar <= 57;
  220. bIsDigit = bChar >= 48 && bChar <= 57;
  221. if (!aIsDigit && !bIsDigit) {
  222. if (aChar < bChar) return -1;
  223. if (aChar > bChar) return 1;
  224. i++;
  225. j++;
  226. } else if (aIsDigit && !bIsDigit) {
  227. // This segment of a is shorter than in b
  228. return 1;
  229. } else if (!aIsDigit && bIsDigit) {
  230. // This segment of b is shorter than in a
  231. return -1;
  232. } else {
  233. let aNumber = aChar - 48;
  234. let bNumber = bChar - 48;
  235. while (++i < aLength) {
  236. aChar = a.charCodeAt(i);
  237. if (aChar < 48 || aChar > 57) break;
  238. aNumber = aNumber * 10 + aChar - 48;
  239. }
  240. while (++j < bLength) {
  241. bChar = b.charCodeAt(j);
  242. if (bChar < 48 || bChar > 57) break;
  243. bNumber = bNumber * 10 + bChar - 48;
  244. }
  245. if (aNumber < bNumber) return -1;
  246. if (aNumber > bNumber) return 1;
  247. }
  248. }
  249. if (j < bLength) {
  250. // a is shorter than b
  251. bChar = b.charCodeAt(j);
  252. bIsDigit = bChar >= 48 && bChar <= 57;
  253. return bIsDigit ? -1 : 1;
  254. }
  255. if (i < aLength) {
  256. // b is shorter than a
  257. aChar = a.charCodeAt(i);
  258. aIsDigit = aChar >= 48 && aChar <= 57;
  259. return aIsDigit ? 1 : -1;
  260. }
  261. return 0;
  262. };
  263. /**
  264. * Compares modules by post order index or identifier.
  265. * @param {ModuleGraph} moduleGraph the module graph
  266. * @param {Module} a module
  267. * @param {Module} b module
  268. * @returns {-1 | 0 | 1} compare result
  269. */
  270. const compareModulesByPostOrderIndexOrIdentifier = (moduleGraph, a, b) => {
  271. const cmp = compareNumbers(
  272. /** @type {number} */ (moduleGraph.getPostOrderIndex(a)),
  273. /** @type {number} */ (moduleGraph.getPostOrderIndex(b))
  274. );
  275. if (cmp !== 0) return cmp;
  276. return compareIds(a.identifier(), b.identifier());
  277. };
  278. /**
  279. * Compares modules by pre order index or identifier.
  280. * @param {ModuleGraph} moduleGraph the module graph
  281. * @param {Module} a module
  282. * @param {Module} b module
  283. * @returns {-1 | 0 | 1} compare result
  284. */
  285. const compareModulesByPreOrderIndexOrIdentifier = (moduleGraph, a, b) => {
  286. const cmp = compareNumbers(
  287. /** @type {number} */ (moduleGraph.getPreOrderIndex(a)),
  288. /** @type {number} */ (moduleGraph.getPreOrderIndex(b))
  289. );
  290. if (cmp !== 0) return cmp;
  291. return compareIds(a.identifier(), b.identifier());
  292. };
  293. /**
  294. * Compares modules by id or identifier.
  295. * @param {ChunkGraph} chunkGraph the chunk graph
  296. * @param {Module} a module
  297. * @param {Module} b module
  298. * @returns {-1 | 0 | 1} compare result
  299. */
  300. const compareModulesByIdOrIdentifier = (chunkGraph, a, b) => {
  301. const cmp = compareIds(
  302. /** @type {ModuleId} */ (chunkGraph.getModuleId(a)),
  303. /** @type {ModuleId} */ (chunkGraph.getModuleId(b))
  304. );
  305. if (cmp !== 0) return cmp;
  306. return compareIds(a.identifier(), b.identifier());
  307. };
  308. /**
  309. * Compare modules by their full name. This differs from comparing by identifier in that the values have been normalized to be relative to the compiler context.
  310. * @param {{ context: string, root: object }} compiler the compiler, used for context and cache
  311. * @param {Module} a module
  312. * @param {Module} b module
  313. * @returns {-1 | 0 | 1} compare result
  314. */
  315. const compareModulesByFullName = (compiler, a, b) => {
  316. const aName = getFullModuleName(a, compiler.context, compiler.root);
  317. const bName = getFullModuleName(b, compiler.context, compiler.root);
  318. return compareIds(aName, bName);
  319. };
  320. /**
  321. * Compares the provided values and returns their ordering.
  322. * @param {ChunkGraph} chunkGraph the chunk graph
  323. * @param {Chunk} a chunk
  324. * @param {Chunk} b chunk
  325. * @returns {-1 | 0 | 1} compare result
  326. */
  327. const compareChunks = (chunkGraph, a, b) => chunkGraph.compareChunks(a, b);
  328. /**
  329. * Compares the provided values and returns their ordering.
  330. * @param {string} a first string
  331. * @param {string} b second string
  332. * @returns {-1 | 0 | 1} compare result
  333. */
  334. const compareStrings = (a, b) => {
  335. if (a < b) return -1;
  336. if (a > b) return 1;
  337. return 0;
  338. };
  339. /**
  340. * Compares chunk groups by index.
  341. * @param {ChunkGroup} a first chunk group
  342. * @param {ChunkGroup} b second chunk group
  343. * @returns {-1 | 0 | 1} compare result
  344. */
  345. const compareChunkGroupsByIndex = (a, b) =>
  346. /** @type {number} */ (a.index) < /** @type {number} */ (b.index) ? -1 : 1;
  347. /**
  348. * Represents TwoKeyWeakMap.
  349. * @template {EXPECTED_OBJECT} K1
  350. * @template {EXPECTED_OBJECT} K2
  351. * @template T
  352. */
  353. class TwoKeyWeakMap {
  354. constructor() {
  355. /**
  356. * @private
  357. * @type {WeakMap<K1, WeakMap<K2, T | undefined>>}
  358. */
  359. this._map = new WeakMap();
  360. }
  361. /**
  362. * Returns value.
  363. * @param {K1} key1 first key
  364. * @param {K2} key2 second key
  365. * @returns {T | undefined} value
  366. */
  367. get(key1, key2) {
  368. const childMap = this._map.get(key1);
  369. if (childMap === undefined) {
  370. return;
  371. }
  372. return childMap.get(key2);
  373. }
  374. /**
  375. * Updates value using the provided key1.
  376. * @param {K1} key1 first key
  377. * @param {K2} key2 second key
  378. * @param {T | undefined} value new value
  379. * @returns {void}
  380. */
  381. set(key1, key2, value) {
  382. let childMap = this._map.get(key1);
  383. if (childMap === undefined) {
  384. childMap = new WeakMap();
  385. this._map.set(key1, childMap);
  386. }
  387. childMap.set(key2, value);
  388. }
  389. }
  390. /** @type {TwoKeyWeakMap<Comparator<EXPECTED_ANY>, Comparator<EXPECTED_ANY>, Comparator<EXPECTED_ANY>>}} */
  391. const concatComparatorsCache = new TwoKeyWeakMap();
  392. /**
  393. * Concat comparators.
  394. * @template T
  395. * @param {Comparator<T>} c1 comparator
  396. * @param {Comparator<T>} c2 comparator
  397. * @param {Comparator<T>[]} cRest comparators
  398. * @returns {Comparator<T>} comparator
  399. */
  400. const concatComparators = (c1, c2, ...cRest) => {
  401. if (cRest.length > 0) {
  402. const [c3, ...cRest2] = cRest;
  403. return concatComparators(c1, concatComparators(c2, c3, ...cRest2));
  404. }
  405. const cacheEntry = /** @type {Comparator<T>} */ (
  406. concatComparatorsCache.get(c1, c2)
  407. );
  408. if (cacheEntry !== undefined) return cacheEntry;
  409. /**
  410. * Returns compare result.
  411. * @param {T} a first value
  412. * @param {T} b second value
  413. * @returns {-1 | 0 | 1} compare result
  414. */
  415. const result = (a, b) => {
  416. const res = c1(a, b);
  417. if (res !== 0) return res;
  418. return c2(a, b);
  419. };
  420. concatComparatorsCache.set(c1, c2, result);
  421. return result;
  422. };
  423. /**
  424. * Defines the selector type used by this module.
  425. * @template A, B
  426. * @typedef {(input: A) => B | undefined | null} Selector
  427. */
  428. /** @type {TwoKeyWeakMap<Selector<EXPECTED_ANY, EXPECTED_ANY>, Comparator<EXPECTED_ANY>, Comparator<EXPECTED_ANY>>}} */
  429. const compareSelectCache = new TwoKeyWeakMap();
  430. /**
  431. * Compares the provided values and returns their ordering.
  432. * @template T
  433. * @template R
  434. * @param {Selector<T, R>} getter getter for value
  435. * @param {Comparator<R>} comparator comparator
  436. * @returns {Comparator<T>} comparator
  437. */
  438. const compareSelect = (getter, comparator) => {
  439. const cacheEntry = compareSelectCache.get(getter, comparator);
  440. if (cacheEntry !== undefined) return cacheEntry;
  441. /**
  442. * Returns compare result.
  443. * @param {T} a first value
  444. * @param {T} b second value
  445. * @returns {-1 | 0 | 1} compare result
  446. */
  447. const result = (a, b) => {
  448. const aValue = getter(a);
  449. const bValue = getter(b);
  450. if (aValue !== undefined && aValue !== null) {
  451. if (bValue !== undefined && bValue !== null) {
  452. return comparator(aValue, bValue);
  453. }
  454. return -1;
  455. }
  456. if (bValue !== undefined && bValue !== null) {
  457. return 1;
  458. }
  459. return 0;
  460. };
  461. compareSelectCache.set(getter, comparator, result);
  462. return result;
  463. };
  464. // `compilation.errors`/`warnings`/`hints` are typed as plain `Error`s, so the
  465. // webpack-specific fields are read through a cast.
  466. const compareErrors = concatComparators(
  467. compareSelect(
  468. /**
  469. * @param {Error} err error
  470. * @returns {string} identifier of the module the error belongs to
  471. */
  472. (err) => {
  473. const { module } = /** @type {WebpackErrorType} */ (err);
  474. return (module && module.identifier()) || "";
  475. },
  476. compareStringsNumeric
  477. ),
  478. compareSelect(
  479. /**
  480. * @param {Error} err error
  481. * @returns {DependencyLocation | undefined} location
  482. */
  483. (err) => /** @type {WebpackErrorType} */ (err).loc,
  484. compareLocations
  485. ),
  486. compareSelect(
  487. /**
  488. * @param {Error} err error
  489. * @returns {string} message
  490. */
  491. (err) => `${err.message}`,
  492. compareStringsNumeric
  493. )
  494. );
  495. /** @type {WeakMap<Comparator<EXPECTED_ANY>, Comparator<Iterable<EXPECTED_ANY>>>} */
  496. const compareIteratorsCache = new WeakMap();
  497. // TODO this is no longer needed when minimum node.js version is >= 12
  498. // since these versions ship with a stable sort function
  499. /**
  500. * Keep original order.
  501. * @template T
  502. * @param {Iterable<T>} iterable original ordered list
  503. * @returns {Comparator<T>} comparator
  504. */
  505. const keepOriginalOrder = (iterable) => {
  506. /** @type {Map<T, number>} */
  507. const map = new Map();
  508. let i = 0;
  509. for (const item of iterable) {
  510. map.set(item, i++);
  511. }
  512. return (a, b) =>
  513. compareNumbers(
  514. /** @type {number} */ (map.get(a)),
  515. /** @type {number} */ (map.get(b))
  516. );
  517. };
  518. /**
  519. * Compares chunks natural.
  520. * @param {ChunkGraph} chunkGraph the chunk graph
  521. * @returns {Comparator<Chunk>} comparator
  522. */
  523. const compareChunksNatural = (chunkGraph) => {
  524. const cmpFn = module.exports.compareModulesById(chunkGraph);
  525. const cmpIterableFn = compareIterables(cmpFn);
  526. return concatComparators(
  527. compareSelect((chunk) => /** @type {ChunkName} */ (chunk.name), compareIds),
  528. compareSelect((chunk) => chunk.runtime, compareRuntime),
  529. compareSelect(
  530. /**
  531. * Handles the callback logic for this hook.
  532. * @param {Chunk} chunk a chunk
  533. * @returns {Iterable<Module>} modules
  534. */
  535. (chunk) => chunkGraph.getOrderedChunkModulesIterable(chunk, cmpFn),
  536. cmpIterableFn
  537. )
  538. );
  539. };
  540. /**
  541. * For HarmonyImportSideEffectDependency and HarmonyImportSpecifierDependency, we should prioritize import order to match the behavior of running modules directly in a JS engine without a bundler.
  542. * For other types like ConstDependency, we can instead prioritize usage order.
  543. * https://github.com/webpack/webpack/pull/19686
  544. * @param {Dependency[]} dependencies dependencies
  545. * @param {WeakMap<Dependency, DependencySourceOrder>} dependencySourceOrderMap dependency source order map
  546. * @param {((dep: Dependency, index: number) => void)=} onDependencyReSort optional callback to set index for each dependency
  547. * @returns {void}
  548. */
  549. const sortWithSourceOrder = (
  550. dependencies,
  551. dependencySourceOrderMap,
  552. onDependencyReSort
  553. ) => {
  554. /** @type {{ dep: Dependency, main: number, sub: number }[]} */
  555. const withSourceOrder = [];
  556. /** @type {number[]} */
  557. const positions = [];
  558. for (let i = 0; i < dependencies.length; i++) {
  559. const dep = dependencies[i];
  560. const cached = dependencySourceOrderMap.get(dep);
  561. if (cached) {
  562. positions.push(i);
  563. withSourceOrder.push({
  564. dep,
  565. main: cached.main,
  566. sub: cached.sub
  567. });
  568. } else {
  569. const sourceOrder = /** @type {number | undefined} */ (
  570. /** @type {ModuleDependency} */ (dep).sourceOrder
  571. );
  572. if (typeof sourceOrder === "number") {
  573. positions.push(i);
  574. withSourceOrder.push({
  575. dep,
  576. main: sourceOrder,
  577. sub: 0
  578. });
  579. }
  580. }
  581. }
  582. if (withSourceOrder.length <= 1) {
  583. return;
  584. }
  585. withSourceOrder.sort((a, b) => {
  586. if (a.main !== b.main) {
  587. return compareNumbers(a.main, b.main);
  588. }
  589. return compareNumbers(a.sub, b.sub);
  590. });
  591. // Second pass: place sorted deps back to original positions
  592. for (let i = 0; i < positions.length; i++) {
  593. const depIndex = positions[i];
  594. dependencies[depIndex] = withSourceOrder[i].dep;
  595. if (onDependencyReSort) {
  596. onDependencyReSort(dependencies[depIndex], depIndex);
  597. }
  598. }
  599. };
  600. module.exports.compareChunkGroupsByIndex = compareChunkGroupsByIndex;
  601. /** @type {ParameterizedComparator<ChunkGraph, Chunk>} */
  602. module.exports.compareChunks =
  603. createCachedParameterizedComparator(compareChunks);
  604. /**
  605. * Returns compare result.
  606. * @param {Chunk} a chunk
  607. * @param {Chunk} b chunk
  608. * @returns {-1 | 0 | 1} compare result
  609. */
  610. module.exports.compareChunksById = (a, b) =>
  611. compareIds(/** @type {ChunkId} */ (a.id), /** @type {ChunkId} */ (b.id));
  612. module.exports.compareChunksNatural = compareChunksNatural;
  613. module.exports.compareErrors = compareErrors;
  614. module.exports.compareIds = compareIds;
  615. module.exports.compareIterables = compareIterables;
  616. module.exports.compareLocations = compareLocations;
  617. /** @type {ParameterizedComparator<Compiler, Module>} */
  618. module.exports.compareModulesByFullName = createCachedParameterizedComparator(
  619. compareModulesByFullName
  620. );
  621. /** @type {ParameterizedComparator<ChunkGraph, Module>} */
  622. module.exports.compareModulesById =
  623. createCachedParameterizedComparator(compareModulesById);
  624. /** @type {ParameterizedComparator<ChunkGraph, Module>} */
  625. module.exports.compareModulesByIdOrIdentifier =
  626. createCachedParameterizedComparator(compareModulesByIdOrIdentifier);
  627. /**
  628. * Returns compare result.
  629. * @param {Module} a module
  630. * @param {Module} b module
  631. * @returns {-1 | 0 | 1} compare result
  632. */
  633. module.exports.compareModulesByIdentifier = (a, b) =>
  634. compareIds(a.identifier(), b.identifier());
  635. /** @type {ParameterizedComparator<ModuleGraph, Module>} */
  636. module.exports.compareModulesByPostOrderIndexOrIdentifier =
  637. createCachedParameterizedComparator(
  638. compareModulesByPostOrderIndexOrIdentifier
  639. );
  640. /** @type {ParameterizedComparator<ModuleGraph, Module>} */
  641. module.exports.compareModulesByPreOrderIndexOrIdentifier =
  642. createCachedParameterizedComparator(
  643. compareModulesByPreOrderIndexOrIdentifier
  644. );
  645. module.exports.compareNumbers = compareNumbers;
  646. module.exports.compareSelect = compareSelect;
  647. module.exports.compareStrings = compareStrings;
  648. module.exports.compareStringsNumeric = compareStringsNumeric;
  649. module.exports.concatComparators = concatComparators;
  650. module.exports.keepOriginalOrder = keepOriginalOrder;
  651. module.exports.sortWithSourceOrder = sortWithSourceOrder;