CodeGenerationResults.js 4.6 KB

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