CodeGenerationResults.js 4.4 KB

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