MultiStats.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const identifierUtils = require("./util/identifier");
  7. /**
  8. * @import {
  9. * StatsOptions,
  10. * StatsValue
  11. * } from "../declarations/WebpackOptions"
  12. */
  13. /**
  14. * @import {
  15. * CreateStatsOptionsContext,
  16. * NormalizedStatsOptions
  17. * } from "./Compilation"
  18. */
  19. /** @import Stats from "./Stats" */
  20. /**
  21. * @import {
  22. * KnownStatsCompilation,
  23. * StatsCompilation,
  24. * StatsError
  25. * } from "./stats/DefaultStatsFactoryPlugin"
  26. */
  27. /**
  28. * Returns indent.
  29. * @param {string} str string
  30. * @param {string} prefix pref
  31. * @returns {string} indent
  32. */
  33. const indent = (str, prefix) => {
  34. const rem = str.replace(/\n([^\n])/g, `\n${prefix}$1`);
  35. return prefix + rem;
  36. };
  37. /** @typedef {StatsOptions} MultiStatsOptions */
  38. /** @typedef {{ version: boolean, hash: boolean, errorsCount: boolean, warningsCount: boolean, errors: boolean, warnings: boolean, hints: boolean, hintsCount: boolean, children: NormalizedStatsOptions[] }} ChildOptions */
  39. class MultiStats {
  40. /**
  41. * Creates an instance of MultiStats.
  42. * @param {Stats[]} stats the child stats
  43. */
  44. constructor(stats) {
  45. /** @type {Stats[]} */
  46. this.stats = stats;
  47. }
  48. get hash() {
  49. return this.stats.map((stat) => stat.hash).join("");
  50. }
  51. /**
  52. * Checks whether this multi stats has errors.
  53. * @returns {boolean} true if a child compilation encountered an error
  54. */
  55. hasErrors() {
  56. return this.stats.some((stat) => stat.hasErrors());
  57. }
  58. /**
  59. * Checks whether this multi stats has warnings.
  60. * @returns {boolean} true if a child compilation had a warning
  61. */
  62. hasWarnings() {
  63. return this.stats.some((stat) => stat.hasWarnings());
  64. }
  65. /**
  66. * Create child options.
  67. * @param {undefined | StatsValue} options stats options
  68. * @param {CreateStatsOptionsContext} context context
  69. * @returns {ChildOptions} context context
  70. */
  71. _createChildOptions(options, context) {
  72. const getCreateStatsOptions = () => {
  73. if (!options) {
  74. options = {};
  75. }
  76. const { children: childrenOptions = undefined, ...baseOptions } =
  77. typeof options === "string"
  78. ? { preset: options }
  79. : /** @type {StatsOptions} */ (options);
  80. return { childrenOptions, baseOptions };
  81. };
  82. const children = this.stats.map((stat, idx) => {
  83. if (typeof options === "boolean") {
  84. return stat.compilation.createStatsOptions(options, context);
  85. }
  86. const { childrenOptions, baseOptions } = getCreateStatsOptions();
  87. const childOptions = Array.isArray(childrenOptions)
  88. ? childrenOptions[idx]
  89. : childrenOptions;
  90. if (typeof childOptions === "boolean") {
  91. return stat.compilation.createStatsOptions(childOptions, context);
  92. }
  93. return stat.compilation.createStatsOptions(
  94. {
  95. ...baseOptions,
  96. ...(typeof childOptions === "string"
  97. ? { preset: childOptions }
  98. : childOptions && typeof childOptions === "object"
  99. ? childOptions
  100. : undefined)
  101. },
  102. context
  103. );
  104. });
  105. return {
  106. version: children.every((o) => o.version),
  107. hash: children.every((o) => o.hash),
  108. errorsCount: children.every((o) => o.errorsCount),
  109. warningsCount: children.every((o) => o.warningsCount),
  110. errors: children.every((o) => o.errors),
  111. warnings: children.every((o) => o.warnings),
  112. hints: children.every((o) => o.hints),
  113. hintsCount: children.every((o) => o.hintsCount),
  114. children
  115. };
  116. }
  117. /**
  118. * Returns json output.
  119. * @param {StatsValue=} options stats options
  120. * @returns {StatsCompilation} json output
  121. */
  122. toJson(options) {
  123. const childOptions = this._createChildOptions(options, {
  124. forToString: false
  125. });
  126. /** @type {KnownStatsCompilation} */
  127. const obj = {};
  128. obj.children = this.stats.map((stat, idx) => {
  129. const obj = stat.toJson(childOptions.children[idx]);
  130. const compilationName = stat.compilation.name;
  131. const name =
  132. compilationName &&
  133. identifierUtils.makePathsRelative(
  134. stat.compilation.compiler.context,
  135. compilationName,
  136. stat.compilation.compiler.root
  137. );
  138. obj.name = name;
  139. return obj;
  140. });
  141. if (childOptions.version) {
  142. obj.version = obj.children[0].version;
  143. }
  144. if (childOptions.hash) {
  145. obj.hash = obj.children.map((j) => j.hash).join("");
  146. }
  147. /**
  148. * Returns result.
  149. * @param {StatsCompilation} j stats error
  150. * @param {StatsError} obj Stats error
  151. * @returns {StatsError} result
  152. */
  153. const mapError = (j, obj) => ({
  154. ...obj,
  155. compilerPath: obj.compilerPath ? `${j.name}.${obj.compilerPath}` : j.name
  156. });
  157. if (childOptions.errors) {
  158. obj.errors = [];
  159. for (const j of obj.children) {
  160. const errors =
  161. /** @type {NonNullable<KnownStatsCompilation["errors"]>} */
  162. (j.errors);
  163. for (const i of errors) {
  164. obj.errors.push(mapError(j, i));
  165. }
  166. }
  167. }
  168. if (childOptions.warnings) {
  169. obj.warnings = [];
  170. for (const j of obj.children) {
  171. const warnings =
  172. /** @type {NonNullable<KnownStatsCompilation["warnings"]>} */
  173. (j.warnings);
  174. for (const i of warnings) {
  175. obj.warnings.push(mapError(j, i));
  176. }
  177. }
  178. }
  179. if (childOptions.hints) {
  180. obj.hints = [];
  181. for (const j of obj.children) {
  182. const hints =
  183. /** @type {NonNullable<KnownStatsCompilation["hints"]>} */
  184. (j.hints);
  185. for (const i of hints) {
  186. obj.hints.push(mapError(j, i));
  187. }
  188. }
  189. }
  190. if (childOptions.errorsCount) {
  191. obj.errorsCount = 0;
  192. for (const j of obj.children) {
  193. obj.errorsCount += /** @type {number} */ (j.errorsCount);
  194. }
  195. }
  196. if (childOptions.warningsCount) {
  197. obj.warningsCount = 0;
  198. for (const j of obj.children) {
  199. obj.warningsCount += /** @type {number} */ (j.warningsCount);
  200. }
  201. }
  202. if (childOptions.hintsCount) {
  203. obj.hintsCount = 0;
  204. for (const j of obj.children) {
  205. obj.hintsCount += /** @type {number} */ (j.hintsCount);
  206. }
  207. }
  208. return obj;
  209. }
  210. /**
  211. * Returns a string representation.
  212. * @param {StatsValue=} options stats options
  213. * @returns {string} string output
  214. */
  215. toString(options) {
  216. const childOptions = this._createChildOptions(options, {
  217. forToString: true
  218. });
  219. const results = this.stats.map((stat, idx) => {
  220. const str = stat.toString(childOptions.children[idx]);
  221. const compilationName = stat.compilation.name;
  222. const name =
  223. compilationName &&
  224. identifierUtils
  225. .makePathsRelative(
  226. stat.compilation.compiler.context,
  227. compilationName,
  228. stat.compilation.compiler.root
  229. )
  230. .replace(/\|/g, " ");
  231. if (!str) return str;
  232. return name ? `${name}:\n${indent(str, " ")}` : str;
  233. });
  234. return results.filter(Boolean).join("\n\n");
  235. }
  236. }
  237. module.exports = MultiStats;