CodeGenerationResults.js 4.9 KB

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