ModuleGraph.js 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const ExportsInfo = require("./ExportsInfo");
  8. const ModuleGraphConnection = require("./ModuleGraphConnection");
  9. const HarmonyImportDependency = require("./dependencies/HarmonyImportDependency");
  10. const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
  11. const SortableSet = require("./util/SortableSet");
  12. const WeakTupleMap = require("./util/WeakTupleMap");
  13. const { sortWithSourceOrder } = require("./util/comparators");
  14. /** @typedef {import("./Compilation").ModuleMemCaches} ModuleMemCaches */
  15. /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
  16. /** @typedef {import("./Dependency")} Dependency */
  17. /** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
  18. /** @typedef {import("./ExportsInfo").ExportInfoName} ExportInfoName */
  19. /** @typedef {import("./Module")} Module */
  20. /** @typedef {import("./ModuleProfile")} ModuleProfile */
  21. /** @typedef {import("./RequestShortener")} RequestShortener */
  22. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  23. /** @typedef {import("./dependencies/HarmonyImportSideEffectDependency")} HarmonyImportSideEffectDependency */
  24. /** @typedef {import("./dependencies/HarmonyImportSpecifierDependency")} HarmonyImportSpecifierDependency */
  25. /** @typedef {import("./util/comparators").DependencySourceOrder} DependencySourceOrder */
  26. /**
  27. * @callback OptimizationBailoutFunction
  28. * @param {RequestShortener} requestShortener
  29. * @returns {string}
  30. */
  31. const EMPTY_SET = new Set();
  32. /**
  33. * @template {Module | null | undefined} T
  34. * @param {SortableSet<ModuleGraphConnection>} set input
  35. * @param {(connection: ModuleGraphConnection) => T} getKey function to extract key from connection
  36. * @returns {ReadonlyMap<T, ReadonlyArray<ModuleGraphConnection>>} mapped by key
  37. */
  38. const getConnectionsByKey = (set, getKey) => {
  39. const map = new Map();
  40. /** @type {T | 0} */
  41. let lastKey = 0;
  42. /** @type {ModuleGraphConnection[] | undefined} */
  43. let lastList;
  44. for (const connection of set) {
  45. const key = getKey(connection);
  46. if (lastKey === key) {
  47. /** @type {ModuleGraphConnection[]} */
  48. (lastList).push(connection);
  49. } else {
  50. lastKey = key;
  51. const list = map.get(key);
  52. if (list !== undefined) {
  53. lastList = list;
  54. list.push(connection);
  55. } else {
  56. const list = [connection];
  57. lastList = list;
  58. map.set(key, list);
  59. }
  60. }
  61. }
  62. return map;
  63. };
  64. /**
  65. * @param {SortableSet<ModuleGraphConnection>} set input
  66. * @returns {ReadonlyMap<Module | undefined | null, ReadonlyArray<ModuleGraphConnection>>} mapped by origin module
  67. */
  68. const getConnectionsByOriginModule = (set) =>
  69. getConnectionsByKey(set, (connection) => connection.originModule);
  70. /**
  71. * @param {SortableSet<ModuleGraphConnection>} set input
  72. * @returns {ReadonlyMap<Module | undefined, ReadonlyArray<ModuleGraphConnection>>} mapped by module
  73. */
  74. const getConnectionsByModule = (set) =>
  75. getConnectionsByKey(set, (connection) => connection.module);
  76. /** @typedef {SortableSet<ModuleGraphConnection>} IncomingConnections */
  77. /** @typedef {SortableSet<ModuleGraphConnection>} OutgoingConnections */
  78. /** @typedef {Module | null | undefined} Issuer */
  79. /** @typedef {(string | OptimizationBailoutFunction)[]} OptimizationBailouts */
  80. class ModuleGraphModule {
  81. constructor() {
  82. /** @type {IncomingConnections} */
  83. this.incomingConnections = new SortableSet();
  84. /** @type {OutgoingConnections | undefined} */
  85. this.outgoingConnections = undefined;
  86. /** @type {Issuer} */
  87. this.issuer = undefined;
  88. /** @type {OptimizationBailouts} */
  89. this.optimizationBailout = [];
  90. /** @type {ExportsInfo} */
  91. this.exports = new ExportsInfo();
  92. /** @type {number | null} */
  93. this.preOrderIndex = null;
  94. /** @type {number | null} */
  95. this.postOrderIndex = null;
  96. /** @type {number | null} */
  97. this.depth = null;
  98. /** @type {ModuleProfile | undefined} */
  99. this.profile = undefined;
  100. /** @type {boolean} */
  101. this.async = false;
  102. /** @type {ModuleGraphConnection[] | undefined} */
  103. this._unassignedConnections = undefined;
  104. }
  105. }
  106. /** @typedef {(moduleGraphConnection: ModuleGraphConnection) => boolean} FilterConnection */
  107. /** @typedef {EXPECTED_OBJECT} MetaKey */
  108. /** @typedef {import("./dependencies/CommonJsExportRequireDependency").idsSymbol} CommonJsExportRequireDependencyIDsSymbol */
  109. /** @typedef {import("./dependencies/HarmonyImportSpecifierDependency").idsSymbol} HarmonyImportSpecifierDependencyIDsSymbol */
  110. /** @typedef {import("./dependencies/HarmonyExportImportedSpecifierDependency").idsSymbol} HarmonyExportImportedSpecifierDependencyIDsSymbol */
  111. /**
  112. * @typedef {object} KnownMeta
  113. * @property {Map<Module, string>=} importVarMap
  114. * @property {Map<Module, string>=} deferredImportVarMap
  115. */
  116. /** @typedef {KnownMeta & Record<CommonJsExportRequireDependencyIDsSymbol | HarmonyImportSpecifierDependencyIDsSymbol | HarmonyExportImportedSpecifierDependencyIDsSymbol, string[]> & Record<string, EXPECTED_ANY>} Meta */
  117. class ModuleGraph {
  118. constructor() {
  119. /**
  120. * @type {WeakMap<Dependency, ModuleGraphConnection | null>}
  121. * @private
  122. */
  123. this._dependencyMap = new WeakMap();
  124. /**
  125. * @type {Map<Module, ModuleGraphModule>}
  126. * @private
  127. */
  128. this._moduleMap = new Map();
  129. /**
  130. * @type {WeakMap<MetaKey, Meta>}
  131. * @private
  132. */
  133. this._metaMap = new WeakMap();
  134. /**
  135. * @type {WeakTupleMap<EXPECTED_ANY[], EXPECTED_ANY> | undefined}
  136. * @private
  137. */
  138. this._cache = undefined;
  139. /**
  140. * @type {ModuleMemCaches | undefined}
  141. * @private
  142. */
  143. this._moduleMemCaches = undefined;
  144. /**
  145. * @type {string | undefined}
  146. * @private
  147. */
  148. this._cacheStage = undefined;
  149. /**
  150. * @type {WeakMap<Dependency, DependencySourceOrder>}
  151. * @private
  152. */
  153. this._dependencySourceOrderMap = new WeakMap();
  154. /**
  155. * @type {Set<Module>}
  156. * @private
  157. */
  158. this._modulesNeedingSort = new Set();
  159. }
  160. /**
  161. * @param {Module} module the module
  162. * @returns {ModuleGraphModule} the internal module
  163. */
  164. _getModuleGraphModule(module) {
  165. let mgm = this._moduleMap.get(module);
  166. if (mgm === undefined) {
  167. mgm = new ModuleGraphModule();
  168. this._moduleMap.set(module, mgm);
  169. }
  170. return mgm;
  171. }
  172. /**
  173. * @param {Dependency} dependency the dependency
  174. * @param {DependenciesBlock} block parent block
  175. * @param {Module} module parent module
  176. * @param {number=} indexInBlock position in block
  177. * @returns {void}
  178. */
  179. setParents(dependency, block, module, indexInBlock = -1) {
  180. dependency._parentDependenciesBlockIndex = indexInBlock;
  181. dependency._parentDependenciesBlock = block;
  182. dependency._parentModule = module;
  183. }
  184. /**
  185. * @param {Dependency} dependency the dependency
  186. * @param {number} index the index
  187. * @returns {void}
  188. */
  189. setParentDependenciesBlockIndex(dependency, index) {
  190. dependency._parentDependenciesBlockIndex = index;
  191. }
  192. /**
  193. * @param {Dependency} dependency the dependency
  194. * @returns {Module | undefined} parent module
  195. */
  196. getParentModule(dependency) {
  197. return dependency._parentModule;
  198. }
  199. /**
  200. * @param {Dependency} dependency the dependency
  201. * @returns {DependenciesBlock | undefined} parent block
  202. */
  203. getParentBlock(dependency) {
  204. return dependency._parentDependenciesBlock;
  205. }
  206. /**
  207. * @param {Dependency} dependency the dependency
  208. * @returns {number} index
  209. */
  210. getParentBlockIndex(dependency) {
  211. return dependency._parentDependenciesBlockIndex;
  212. }
  213. /**
  214. * @param {Module | null} originModule the referencing module
  215. * @param {Dependency} dependency the referencing dependency
  216. * @param {Module} module the referenced module
  217. * @returns {void}
  218. */
  219. setResolvedModule(originModule, dependency, module) {
  220. const connection = new ModuleGraphConnection(
  221. originModule,
  222. dependency,
  223. module,
  224. undefined,
  225. dependency.weak,
  226. dependency.getCondition(this)
  227. );
  228. const connections = this._getModuleGraphModule(module).incomingConnections;
  229. connections.add(connection);
  230. if (originModule) {
  231. const mgm = this._getModuleGraphModule(originModule);
  232. if (mgm._unassignedConnections === undefined) {
  233. mgm._unassignedConnections = [];
  234. }
  235. mgm._unassignedConnections.push(connection);
  236. if (mgm.outgoingConnections === undefined) {
  237. mgm.outgoingConnections = new SortableSet();
  238. }
  239. mgm.outgoingConnections.add(connection);
  240. } else {
  241. this._dependencyMap.set(dependency, connection);
  242. }
  243. }
  244. /**
  245. * @param {Dependency} dependency the referencing dependency
  246. * @param {Module} module the referenced module
  247. * @returns {void}
  248. */
  249. updateModule(dependency, module) {
  250. const connection =
  251. /** @type {ModuleGraphConnection} */
  252. (this.getConnection(dependency));
  253. if (connection.module === module) return;
  254. const newConnection = connection.clone();
  255. newConnection.module = module;
  256. this._dependencyMap.set(dependency, newConnection);
  257. connection.setActive(false);
  258. const originMgm = this._getModuleGraphModule(
  259. /** @type {Module} */ (connection.originModule)
  260. );
  261. /** @type {OutgoingConnections} */
  262. (originMgm.outgoingConnections).add(newConnection);
  263. const targetMgm = this._getModuleGraphModule(module);
  264. targetMgm.incomingConnections.add(newConnection);
  265. }
  266. /**
  267. * @param {Dependency} dependency the need update dependency
  268. * @param {ModuleGraphConnection=} connection the target connection
  269. * @param {Module=} parentModule the parent module
  270. * @returns {void}
  271. */
  272. updateParent(dependency, connection, parentModule) {
  273. if (this._dependencySourceOrderMap.has(dependency)) {
  274. return;
  275. }
  276. if (!connection || !parentModule) {
  277. return;
  278. }
  279. const originDependency = connection.dependency;
  280. // src/index.js
  281. // import { c } from "lib/c" -> c = 0
  282. // import { a, b } from "lib" -> a and b have the same source order -> a = b = 1
  283. // import { d } from "lib/d" -> d = 2
  284. const currentSourceOrder =
  285. /** @type {HarmonyImportSideEffectDependency | HarmonyImportSpecifierDependency} */
  286. (dependency).sourceOrder;
  287. // lib/index.js (reexport)
  288. // import { a } from "lib/a" -> a = 0
  289. // import { b } from "lib/b" -> b = 1
  290. const originSourceOrder =
  291. /** @type {HarmonyImportSideEffectDependency | HarmonyImportSpecifierDependency} */
  292. (originDependency).sourceOrder;
  293. if (
  294. typeof currentSourceOrder === "number" &&
  295. typeof originSourceOrder === "number"
  296. ) {
  297. // src/index.js
  298. // import { c } from "lib/c" -> c = 0
  299. // import { a } from "lib/a" -> a = 1.0 = 1(main) + 0.0(sub)
  300. // import { b } from "lib/b" -> b = 1.1 = 1(main) + 0.1(sub)
  301. // import { d } from "lib/d" -> d = 2
  302. this._dependencySourceOrderMap.set(dependency, {
  303. main: currentSourceOrder,
  304. sub: originSourceOrder
  305. });
  306. // Save for later batch sorting
  307. this._modulesNeedingSort.add(parentModule);
  308. }
  309. }
  310. /**
  311. * @returns {void}
  312. */
  313. finishUpdateParent() {
  314. if (this._modulesNeedingSort.size === 0) {
  315. return;
  316. }
  317. for (const mod of this._modulesNeedingSort) {
  318. // If dependencies like HarmonyImportSideEffectDependency and HarmonyImportSpecifierDependency have a SourceOrder,
  319. // we sort based on it; otherwise, we preserve the original order.
  320. sortWithSourceOrder(
  321. mod.dependencies,
  322. this._dependencySourceOrderMap,
  323. (dep, index) => this.setParentDependenciesBlockIndex(dep, index)
  324. );
  325. }
  326. this._modulesNeedingSort.clear();
  327. }
  328. /**
  329. * @param {Dependency} dependency the referencing dependency
  330. * @returns {void}
  331. */
  332. removeConnection(dependency) {
  333. const connection =
  334. /** @type {ModuleGraphConnection} */
  335. (this.getConnection(dependency));
  336. const targetMgm = this._getModuleGraphModule(connection.module);
  337. targetMgm.incomingConnections.delete(connection);
  338. const originMgm = this._getModuleGraphModule(
  339. /** @type {Module} */ (connection.originModule)
  340. );
  341. /** @type {OutgoingConnections} */
  342. (originMgm.outgoingConnections).delete(connection);
  343. this._dependencyMap.set(dependency, null);
  344. }
  345. /**
  346. * @param {Dependency} dependency the referencing dependency
  347. * @param {string} explanation an explanation
  348. * @returns {void}
  349. */
  350. addExplanation(dependency, explanation) {
  351. const connection =
  352. /** @type {ModuleGraphConnection} */
  353. (this.getConnection(dependency));
  354. connection.addExplanation(explanation);
  355. }
  356. /**
  357. * @param {Module} sourceModule the source module
  358. * @param {Module} targetModule the target module
  359. * @returns {void}
  360. */
  361. cloneModuleAttributes(sourceModule, targetModule) {
  362. const oldMgm = this._getModuleGraphModule(sourceModule);
  363. const newMgm = this._getModuleGraphModule(targetModule);
  364. newMgm.postOrderIndex = oldMgm.postOrderIndex;
  365. newMgm.preOrderIndex = oldMgm.preOrderIndex;
  366. newMgm.depth = oldMgm.depth;
  367. newMgm.exports = oldMgm.exports;
  368. newMgm.async = oldMgm.async;
  369. }
  370. /**
  371. * @param {Module} module the module
  372. * @returns {void}
  373. */
  374. removeModuleAttributes(module) {
  375. const mgm = this._getModuleGraphModule(module);
  376. mgm.postOrderIndex = null;
  377. mgm.preOrderIndex = null;
  378. mgm.depth = null;
  379. mgm.async = false;
  380. }
  381. /**
  382. * @returns {void}
  383. */
  384. removeAllModuleAttributes() {
  385. for (const mgm of this._moduleMap.values()) {
  386. mgm.postOrderIndex = null;
  387. mgm.preOrderIndex = null;
  388. mgm.depth = null;
  389. mgm.async = false;
  390. }
  391. }
  392. /**
  393. * @param {Module} oldModule the old referencing module
  394. * @param {Module} newModule the new referencing module
  395. * @param {FilterConnection} filterConnection filter predicate for replacement
  396. * @returns {void}
  397. */
  398. moveModuleConnections(oldModule, newModule, filterConnection) {
  399. if (oldModule === newModule) return;
  400. const oldMgm = this._getModuleGraphModule(oldModule);
  401. const newMgm = this._getModuleGraphModule(newModule);
  402. // Outgoing connections
  403. const oldConnections = oldMgm.outgoingConnections;
  404. if (oldConnections !== undefined) {
  405. if (newMgm.outgoingConnections === undefined) {
  406. newMgm.outgoingConnections = new SortableSet();
  407. }
  408. const newConnections = newMgm.outgoingConnections;
  409. for (const connection of oldConnections) {
  410. if (filterConnection(connection)) {
  411. connection.originModule = newModule;
  412. newConnections.add(connection);
  413. oldConnections.delete(connection);
  414. }
  415. }
  416. }
  417. // Incoming connections
  418. const oldConnections2 = oldMgm.incomingConnections;
  419. const newConnections2 = newMgm.incomingConnections;
  420. for (const connection of oldConnections2) {
  421. if (filterConnection(connection)) {
  422. connection.module = newModule;
  423. newConnections2.add(connection);
  424. oldConnections2.delete(connection);
  425. }
  426. }
  427. }
  428. /**
  429. * @param {Module} oldModule the old referencing module
  430. * @param {Module} newModule the new referencing module
  431. * @param {FilterConnection} filterConnection filter predicate for replacement
  432. * @returns {void}
  433. */
  434. copyOutgoingModuleConnections(oldModule, newModule, filterConnection) {
  435. if (oldModule === newModule) return;
  436. const oldMgm = this._getModuleGraphModule(oldModule);
  437. const newMgm = this._getModuleGraphModule(newModule);
  438. // Outgoing connections
  439. const oldConnections = oldMgm.outgoingConnections;
  440. if (oldConnections !== undefined) {
  441. if (newMgm.outgoingConnections === undefined) {
  442. newMgm.outgoingConnections = new SortableSet();
  443. }
  444. const newConnections = newMgm.outgoingConnections;
  445. for (const connection of oldConnections) {
  446. if (filterConnection(connection)) {
  447. const newConnection = connection.clone();
  448. newConnection.originModule = newModule;
  449. newConnections.add(newConnection);
  450. if (newConnection.module !== undefined) {
  451. const otherMgm = this._getModuleGraphModule(newConnection.module);
  452. otherMgm.incomingConnections.add(newConnection);
  453. }
  454. }
  455. }
  456. }
  457. }
  458. /**
  459. * @param {Module} module the referenced module
  460. * @param {string} explanation an explanation why it's referenced
  461. * @returns {void}
  462. */
  463. addExtraReason(module, explanation) {
  464. const connections = this._getModuleGraphModule(module).incomingConnections;
  465. connections.add(new ModuleGraphConnection(null, null, module, explanation));
  466. }
  467. /**
  468. * @param {Dependency} dependency the dependency to look for a referenced module
  469. * @returns {Module | null} the referenced module
  470. */
  471. getResolvedModule(dependency) {
  472. const connection = this.getConnection(dependency);
  473. return connection !== undefined ? connection.resolvedModule : null;
  474. }
  475. /**
  476. * @param {Dependency} dependency the dependency to look for a referenced module
  477. * @returns {ModuleGraphConnection | undefined} the connection
  478. */
  479. getConnection(dependency) {
  480. const connection = this._dependencyMap.get(dependency);
  481. if (connection === undefined) {
  482. const module = this.getParentModule(dependency);
  483. if (module !== undefined) {
  484. const mgm = this._getModuleGraphModule(module);
  485. if (
  486. mgm._unassignedConnections &&
  487. mgm._unassignedConnections.length !== 0
  488. ) {
  489. let foundConnection;
  490. for (const connection of mgm._unassignedConnections) {
  491. this._dependencyMap.set(
  492. /** @type {Dependency} */ (connection.dependency),
  493. connection
  494. );
  495. if (connection.dependency === dependency) {
  496. foundConnection = connection;
  497. }
  498. }
  499. mgm._unassignedConnections.length = 0;
  500. if (foundConnection !== undefined) {
  501. return foundConnection;
  502. }
  503. }
  504. }
  505. this._dependencyMap.set(dependency, null);
  506. return;
  507. }
  508. return connection === null ? undefined : connection;
  509. }
  510. /**
  511. * @param {Dependency} dependency the dependency to look for a referenced module
  512. * @returns {Module | null} the referenced module
  513. */
  514. getModule(dependency) {
  515. const connection = this.getConnection(dependency);
  516. return connection !== undefined ? connection.module : null;
  517. }
  518. /**
  519. * @param {Dependency} dependency the dependency to look for a referencing module
  520. * @returns {Module | null} the referencing module
  521. */
  522. getOrigin(dependency) {
  523. const connection = this.getConnection(dependency);
  524. return connection !== undefined ? connection.originModule : null;
  525. }
  526. /**
  527. * @param {Dependency} dependency the dependency to look for a referencing module
  528. * @returns {Module | null} the original referencing module
  529. */
  530. getResolvedOrigin(dependency) {
  531. const connection = this.getConnection(dependency);
  532. return connection !== undefined ? connection.resolvedOriginModule : null;
  533. }
  534. /**
  535. * @param {Module} module the module
  536. * @returns {Iterable<ModuleGraphConnection>} reasons why a module is included
  537. */
  538. getIncomingConnections(module) {
  539. const connections = this._getModuleGraphModule(module).incomingConnections;
  540. return connections;
  541. }
  542. /**
  543. * @param {Module} module the module
  544. * @returns {Iterable<ModuleGraphConnection>} list of outgoing connections
  545. */
  546. getOutgoingConnections(module) {
  547. const connections = this._getModuleGraphModule(module).outgoingConnections;
  548. return connections === undefined ? EMPTY_SET : connections;
  549. }
  550. /**
  551. * @param {Module} module the module
  552. * @returns {ReadonlyMap<Module | undefined | null, ReadonlyArray<ModuleGraphConnection>>} reasons why a module is included, in a map by source module
  553. */
  554. getIncomingConnectionsByOriginModule(module) {
  555. const connections = this._getModuleGraphModule(module).incomingConnections;
  556. return connections.getFromUnorderedCache(getConnectionsByOriginModule);
  557. }
  558. /**
  559. * @param {Module} module the module
  560. * @returns {ReadonlyMap<Module | undefined, ReadonlyArray<ModuleGraphConnection>> | undefined} connections to modules, in a map by module
  561. */
  562. getOutgoingConnectionsByModule(module) {
  563. const connections = this._getModuleGraphModule(module).outgoingConnections;
  564. return connections === undefined
  565. ? undefined
  566. : connections.getFromUnorderedCache(getConnectionsByModule);
  567. }
  568. /**
  569. * @param {Module} module the module
  570. * @returns {ModuleProfile | undefined} the module profile
  571. */
  572. getProfile(module) {
  573. const mgm = this._getModuleGraphModule(module);
  574. return mgm.profile;
  575. }
  576. /**
  577. * @param {Module} module the module
  578. * @param {ModuleProfile | undefined} profile the module profile
  579. * @returns {void}
  580. */
  581. setProfile(module, profile) {
  582. const mgm = this._getModuleGraphModule(module);
  583. mgm.profile = profile;
  584. }
  585. /**
  586. * @param {Module} module the module
  587. * @returns {Issuer} the issuer module
  588. */
  589. getIssuer(module) {
  590. const mgm = this._getModuleGraphModule(module);
  591. return mgm.issuer;
  592. }
  593. /**
  594. * @param {Module} module the module
  595. * @param {Module | null} issuer the issuer module
  596. * @returns {void}
  597. */
  598. setIssuer(module, issuer) {
  599. const mgm = this._getModuleGraphModule(module);
  600. mgm.issuer = issuer;
  601. }
  602. /**
  603. * @param {Module} module the module
  604. * @param {Module | null} issuer the issuer module
  605. * @returns {void}
  606. */
  607. setIssuerIfUnset(module, issuer) {
  608. const mgm = this._getModuleGraphModule(module);
  609. if (mgm.issuer === undefined) mgm.issuer = issuer;
  610. }
  611. /**
  612. * @param {Module} module the module
  613. * @returns {OptimizationBailouts} optimization bailouts
  614. */
  615. getOptimizationBailout(module) {
  616. const mgm = this._getModuleGraphModule(module);
  617. return mgm.optimizationBailout;
  618. }
  619. /**
  620. * @param {Module} module the module
  621. * @returns {null | true | ExportInfoName[]} the provided exports
  622. */
  623. getProvidedExports(module) {
  624. const mgm = this._getModuleGraphModule(module);
  625. return mgm.exports.getProvidedExports();
  626. }
  627. /**
  628. * @param {Module} module the module
  629. * @param {ExportInfoName | ExportInfoName[]} exportName a name of an export
  630. * @returns {boolean | null} true, if the export is provided by the module.
  631. * null, if it's unknown.
  632. * false, if it's not provided.
  633. */
  634. isExportProvided(module, exportName) {
  635. const mgm = this._getModuleGraphModule(module);
  636. const result = mgm.exports.isExportProvided(exportName);
  637. return result === undefined ? null : result;
  638. }
  639. /**
  640. * @param {Module} module the module
  641. * @returns {ExportsInfo} info about the exports
  642. */
  643. getExportsInfo(module) {
  644. const mgm = this._getModuleGraphModule(module);
  645. return mgm.exports;
  646. }
  647. /**
  648. * @param {Module} module the module
  649. * @param {string} exportName the export
  650. * @returns {ExportInfo} info about the export
  651. */
  652. getExportInfo(module, exportName) {
  653. const mgm = this._getModuleGraphModule(module);
  654. return mgm.exports.getExportInfo(exportName);
  655. }
  656. /**
  657. * @param {Module} module the module
  658. * @param {string} exportName the export
  659. * @returns {ExportInfo} info about the export (do not modify)
  660. */
  661. getReadOnlyExportInfo(module, exportName) {
  662. const mgm = this._getModuleGraphModule(module);
  663. return mgm.exports.getReadOnlyExportInfo(exportName);
  664. }
  665. /**
  666. * @param {Module} module the module
  667. * @param {RuntimeSpec} runtime the runtime
  668. * @returns {false | true | SortableSet<string> | null} the used exports
  669. * false: module is not used at all.
  670. * true: the module namespace/object export is used.
  671. * SortableSet<string>: these export names are used.
  672. * empty SortableSet<string>: module is used but no export.
  673. * null: unknown, worst case should be assumed.
  674. */
  675. getUsedExports(module, runtime) {
  676. const mgm = this._getModuleGraphModule(module);
  677. return mgm.exports.getUsedExports(runtime);
  678. }
  679. /**
  680. * @param {Module} module the module
  681. * @returns {number | null} the index of the module
  682. */
  683. getPreOrderIndex(module) {
  684. const mgm = this._getModuleGraphModule(module);
  685. return mgm.preOrderIndex;
  686. }
  687. /**
  688. * @param {Module} module the module
  689. * @returns {number | null} the index of the module
  690. */
  691. getPostOrderIndex(module) {
  692. const mgm = this._getModuleGraphModule(module);
  693. return mgm.postOrderIndex;
  694. }
  695. /**
  696. * @param {Module} module the module
  697. * @param {number} index the index of the module
  698. * @returns {void}
  699. */
  700. setPreOrderIndex(module, index) {
  701. const mgm = this._getModuleGraphModule(module);
  702. mgm.preOrderIndex = index;
  703. }
  704. /**
  705. * @param {Module} module the module
  706. * @param {number} index the index of the module
  707. * @returns {boolean} true, if the index was set
  708. */
  709. setPreOrderIndexIfUnset(module, index) {
  710. const mgm = this._getModuleGraphModule(module);
  711. if (mgm.preOrderIndex === null) {
  712. mgm.preOrderIndex = index;
  713. return true;
  714. }
  715. return false;
  716. }
  717. /**
  718. * @param {Module} module the module
  719. * @param {number} index the index of the module
  720. * @returns {void}
  721. */
  722. setPostOrderIndex(module, index) {
  723. const mgm = this._getModuleGraphModule(module);
  724. mgm.postOrderIndex = index;
  725. }
  726. /**
  727. * @param {Module} module the module
  728. * @param {number} index the index of the module
  729. * @returns {boolean} true, if the index was set
  730. */
  731. setPostOrderIndexIfUnset(module, index) {
  732. const mgm = this._getModuleGraphModule(module);
  733. if (mgm.postOrderIndex === null) {
  734. mgm.postOrderIndex = index;
  735. return true;
  736. }
  737. return false;
  738. }
  739. /**
  740. * @param {Module} module the module
  741. * @returns {number | null} the depth of the module
  742. */
  743. getDepth(module) {
  744. const mgm = this._getModuleGraphModule(module);
  745. return mgm.depth;
  746. }
  747. /**
  748. * @param {Module} module the module
  749. * @param {number} depth the depth of the module
  750. * @returns {void}
  751. */
  752. setDepth(module, depth) {
  753. const mgm = this._getModuleGraphModule(module);
  754. mgm.depth = depth;
  755. }
  756. /**
  757. * @param {Module} module the module
  758. * @param {number} depth the depth of the module
  759. * @returns {boolean} true, if the depth was set
  760. */
  761. setDepthIfLower(module, depth) {
  762. const mgm = this._getModuleGraphModule(module);
  763. if (mgm.depth === null || mgm.depth > depth) {
  764. mgm.depth = depth;
  765. return true;
  766. }
  767. return false;
  768. }
  769. /**
  770. * @param {Module} module the module
  771. * @returns {boolean} true, if the module is async
  772. */
  773. isAsync(module) {
  774. const mgm = this._getModuleGraphModule(module);
  775. return mgm.async;
  776. }
  777. /**
  778. * @param {Module} module the module
  779. * @returns {boolean} true, if the module is used as a deferred module at least once
  780. */
  781. isDeferred(module) {
  782. if (this.isAsync(module)) return false;
  783. const connections = this.getIncomingConnections(module);
  784. for (const connection of connections) {
  785. if (
  786. !connection.dependency ||
  787. !(connection.dependency instanceof HarmonyImportDependency)
  788. ) {
  789. continue;
  790. }
  791. if (ImportPhaseUtils.isDefer(connection.dependency.phase)) return true;
  792. }
  793. return false;
  794. }
  795. /**
  796. * @param {Module} module the module
  797. * @returns {void}
  798. */
  799. setAsync(module) {
  800. const mgm = this._getModuleGraphModule(module);
  801. mgm.async = true;
  802. }
  803. /**
  804. * @param {MetaKey} thing any thing
  805. * @returns {Meta} metadata
  806. */
  807. getMeta(thing) {
  808. let meta = this._metaMap.get(thing);
  809. if (meta === undefined) {
  810. meta = /** @type {Meta} */ (Object.create(null));
  811. this._metaMap.set(thing, meta);
  812. }
  813. return meta;
  814. }
  815. /**
  816. * @param {MetaKey} thing any thing
  817. * @returns {Meta | undefined} metadata
  818. */
  819. getMetaIfExisting(thing) {
  820. return this._metaMap.get(thing);
  821. }
  822. /**
  823. * @param {string=} cacheStage a persistent stage name for caching
  824. */
  825. freeze(cacheStage) {
  826. this._cache = new WeakTupleMap();
  827. this._cacheStage = cacheStage;
  828. }
  829. unfreeze() {
  830. this._cache = undefined;
  831. this._cacheStage = undefined;
  832. }
  833. /**
  834. * @template {EXPECTED_ANY[]} T
  835. * @template R
  836. * @param {(moduleGraph: ModuleGraph, ...args: T) => R} fn computer
  837. * @param {T} args arguments
  838. * @returns {R} computed value or cached
  839. */
  840. cached(fn, ...args) {
  841. if (this._cache === undefined) return fn(this, ...args);
  842. return this._cache.provide(fn, ...args, () => fn(this, ...args));
  843. }
  844. /**
  845. * @param {ModuleMemCaches} moduleMemCaches mem caches for modules for better caching
  846. */
  847. setModuleMemCaches(moduleMemCaches) {
  848. this._moduleMemCaches = moduleMemCaches;
  849. }
  850. /**
  851. * @template {Dependency} D
  852. * @template {EXPECTED_ANY[]} ARGS
  853. * @template R
  854. * @param {D} dependency dependency
  855. * @param {[...ARGS, (moduleGraph: ModuleGraph, dependency: D, ...args: ARGS) => R]} args arguments, last argument is a function called with moduleGraph, dependency, ...args
  856. * @returns {R} computed value or cached
  857. */
  858. dependencyCacheProvide(dependency, ...args) {
  859. const fn =
  860. /** @type {(moduleGraph: ModuleGraph, dependency: D, ...args: EXPECTED_ANY[]) => R} */
  861. (args.pop());
  862. if (this._moduleMemCaches && this._cacheStage) {
  863. const memCache = this._moduleMemCaches.get(
  864. /** @type {Module} */
  865. (this.getParentModule(dependency))
  866. );
  867. if (memCache !== undefined) {
  868. return memCache.provide(dependency, this._cacheStage, ...args, () =>
  869. fn(this, dependency, ...args)
  870. );
  871. }
  872. }
  873. if (this._cache === undefined) return fn(this, dependency, ...args);
  874. return this._cache.provide(dependency, ...args, () =>
  875. fn(this, dependency, ...args)
  876. );
  877. }
  878. // TODO remove in webpack 6
  879. /**
  880. * @param {Module} module the module
  881. * @param {string} deprecateMessage message for the deprecation message
  882. * @param {string} deprecationCode code for the deprecation
  883. * @returns {ModuleGraph} the module graph
  884. */
  885. static getModuleGraphForModule(module, deprecateMessage, deprecationCode) {
  886. const fn = deprecateMap.get(deprecateMessage);
  887. if (fn) return fn(module);
  888. const newFn = util.deprecate(
  889. /**
  890. * @param {Module} module the module
  891. * @returns {ModuleGraph} the module graph
  892. */
  893. (module) => {
  894. const moduleGraph = moduleGraphForModuleMap.get(module);
  895. if (!moduleGraph) {
  896. throw new Error(
  897. `${
  898. deprecateMessage
  899. }There was no ModuleGraph assigned to the Module for backward-compat (Use the new API)`
  900. );
  901. }
  902. return moduleGraph;
  903. },
  904. `${deprecateMessage}: Use new ModuleGraph API`,
  905. deprecationCode
  906. );
  907. deprecateMap.set(deprecateMessage, newFn);
  908. return newFn(module);
  909. }
  910. // TODO remove in webpack 6
  911. /**
  912. * @param {Module} module the module
  913. * @param {ModuleGraph} moduleGraph the module graph
  914. * @returns {void}
  915. */
  916. static setModuleGraphForModule(module, moduleGraph) {
  917. moduleGraphForModuleMap.set(module, moduleGraph);
  918. }
  919. // TODO remove in webpack 6
  920. /**
  921. * @param {Module} module the module
  922. * @returns {void}
  923. */
  924. static clearModuleGraphForModule(module) {
  925. moduleGraphForModuleMap.delete(module);
  926. }
  927. }
  928. // TODO remove in webpack 6
  929. /** @type {WeakMap<Module, ModuleGraph>} */
  930. const moduleGraphForModuleMap = new WeakMap();
  931. // TODO remove in webpack 6
  932. /** @type {Map<string, (module: Module) => ModuleGraph>} */
  933. const deprecateMap = new Map();
  934. module.exports = ModuleGraph;
  935. module.exports.ModuleGraphConnection = ModuleGraphConnection;