提交学习笔记专用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1005 lines
29 KiB

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