ModuleGraph.js 32 KB

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