提交学习笔记专用
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.

159 lines
4.7 KiB

  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { DEFAULTS } = require("./config/defaults");
  7. const { getOrInsert } = require("./util/MapHelpers");
  8. const { first } = require("./util/SetHelpers");
  9. const createHash = require("./util/createHash");
  10. const { RuntimeSpecMap, runtimeToString } = require("./util/runtime");
  11. /** @typedef {import("webpack-sources").Source} Source */
  12. /** @typedef {import("./Module")} Module */
  13. /** @typedef {import("./Module").CodeGenerationResult} CodeGenerationResult */
  14. /** @typedef {import("./Module").CodeGenerationResultData} CodeGenerationResultData */
  15. /** @typedef {import("./Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
  16. /** @typedef {typeof import("./util/Hash")} Hash */
  17. /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
  18. class CodeGenerationResults {
  19. /**
  20. * @param {string | Hash} hashFunction the hash function to use
  21. */
  22. constructor(hashFunction = DEFAULTS.HASH_FUNCTION) {
  23. /** @type {Map<Module, RuntimeSpecMap<CodeGenerationResult>>} */
  24. this.map = new Map();
  25. this._hashFunction = hashFunction;
  26. }
  27. /**
  28. * @param {Module} module the module
  29. * @param {RuntimeSpec} runtime runtime(s)
  30. * @returns {CodeGenerationResult} the CodeGenerationResult
  31. */
  32. get(module, runtime) {
  33. const entry = this.map.get(module);
  34. if (entry === undefined) {
  35. throw new Error(
  36. `No code generation entry for ${module.identifier()} (existing entries: ${Array.from(
  37. this.map.keys(),
  38. (m) => m.identifier()
  39. ).join(", ")})`
  40. );
  41. }
  42. if (runtime === undefined) {
  43. if (entry.size > 1) {
  44. const results = new Set(entry.values());
  45. if (results.size !== 1) {
  46. throw new Error(
  47. `No unique code generation entry for unspecified runtime for ${module.identifier()} (existing runtimes: ${Array.from(
  48. entry.keys(),
  49. (r) => runtimeToString(r)
  50. ).join(", ")}).
  51. Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
  52. );
  53. }
  54. return /** @type {CodeGenerationResult} */ (first(results));
  55. }
  56. return /** @type {CodeGenerationResult} */ (entry.values().next().value);
  57. }
  58. const result = entry.get(runtime);
  59. if (result === undefined) {
  60. throw new Error(
  61. `No code generation entry for runtime ${runtimeToString(
  62. runtime
  63. )} for ${module.identifier()} (existing runtimes: ${Array.from(
  64. entry.keys(),
  65. (r) => runtimeToString(r)
  66. ).join(", ")})`
  67. );
  68. }
  69. return result;
  70. }
  71. /**
  72. * @param {Module} module the module
  73. * @param {RuntimeSpec} runtime runtime(s)
  74. * @returns {boolean} true, when we have data for this
  75. */
  76. has(module, runtime) {
  77. const entry = this.map.get(module);
  78. if (entry === undefined) {
  79. return false;
  80. }
  81. if (runtime !== undefined) {
  82. return entry.has(runtime);
  83. } else if (entry.size > 1) {
  84. const results = new Set(entry.values());
  85. return results.size === 1;
  86. }
  87. return entry.size === 1;
  88. }
  89. /**
  90. * @param {Module} module the module
  91. * @param {RuntimeSpec} runtime runtime(s)
  92. * @param {string} sourceType the source type
  93. * @returns {Source} a source
  94. */
  95. getSource(module, runtime, sourceType) {
  96. return /** @type {Source} */ (
  97. this.get(module, runtime).sources.get(sourceType)
  98. );
  99. }
  100. /**
  101. * @param {Module} module the module
  102. * @param {RuntimeSpec} runtime runtime(s)
  103. * @returns {ReadOnlyRuntimeRequirements | null} runtime requirements
  104. */
  105. getRuntimeRequirements(module, runtime) {
  106. return this.get(module, runtime).runtimeRequirements;
  107. }
  108. /**
  109. * @param {Module} module the module
  110. * @param {RuntimeSpec} runtime runtime(s)
  111. * @param {string} key data key
  112. * @returns {ReturnType<CodeGenerationResultData["get"]>} data generated by code generation
  113. */
  114. getData(module, runtime, key) {
  115. const data = this.get(module, runtime).data;
  116. return data === undefined ? undefined : data.get(key);
  117. }
  118. /**
  119. * @param {Module} module the module
  120. * @param {RuntimeSpec} runtime runtime(s)
  121. * @returns {string} hash of the code generation
  122. */
  123. getHash(module, runtime) {
  124. const info = this.get(module, runtime);
  125. if (info.hash !== undefined) return info.hash;
  126. const hash = createHash(this._hashFunction);
  127. for (const [type, source] of info.sources) {
  128. hash.update(type);
  129. source.updateHash(hash);
  130. }
  131. if (info.runtimeRequirements) {
  132. for (const rr of info.runtimeRequirements) hash.update(rr);
  133. }
  134. return (info.hash = hash.digest("hex"));
  135. }
  136. /**
  137. * @param {Module} module the module
  138. * @param {RuntimeSpec} runtime runtime(s)
  139. * @param {CodeGenerationResult} result result from module
  140. * @returns {void}
  141. */
  142. add(module, runtime, result) {
  143. const map = getOrInsert(this.map, module, () => new RuntimeSpecMap());
  144. map.set(runtime, result);
  145. }
  146. }
  147. module.exports = CodeGenerationResults;