MultiStats.js 6.2 KB

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