DefaultStatsPrinterPlugin.js 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /** @typedef {import("../Compiler")} Compiler */
  7. /** @typedef {import("../logging/Logger").LogTypeEnum} LogTypeEnum */
  8. /** @typedef {import("./DefaultStatsFactoryPlugin").ChunkId} ChunkId */
  9. /** @typedef {import("./DefaultStatsFactoryPlugin").ChunkName} ChunkName */
  10. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsAsset} KnownStatsAsset */
  11. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsChunk} KnownStatsChunk */
  12. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsChunkGroup} KnownStatsChunkGroup */
  13. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsChunkOrigin} KnownStatsChunkOrigin */
  14. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsCompilation} KnownStatsCompilation */
  15. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsError} KnownStatsError */
  16. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsLogging} KnownStatsLogging */
  17. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsLoggingEntry} KnownStatsLoggingEntry */
  18. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsModule} KnownStatsModule */
  19. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsModuleIssuer} KnownStatsModuleIssuer */
  20. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsModuleReason} KnownStatsModuleReason */
  21. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsModuleTraceDependency} KnownStatsModuleTraceDependency */
  22. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsModuleTraceItem} KnownStatsModuleTraceItem */
  23. /** @typedef {import("./DefaultStatsFactoryPlugin").KnownStatsProfile} KnownStatsProfile */
  24. /** @typedef {import("./DefaultStatsFactoryPlugin").StatsCompilation} StatsCompilation */
  25. /** @typedef {import("./StatsPrinter")} StatsPrinter */
  26. /** @typedef {import("./StatsPrinter").ColorFunction} ColorFunction */
  27. /** @typedef {import("./StatsPrinter").KnownStatsPrinterColorFunctions} KnownStatsPrinterColorFunctions */
  28. /** @typedef {import("./StatsPrinter").KnownStatsPrinterContext} KnownStatsPrinterContext */
  29. /** @typedef {import("./StatsPrinter").KnownStatsPrinterFormatters} KnownStatsPrinterFormatters */
  30. /** @typedef {import("./StatsPrinter").StatsPrinterContext} StatsPrinterContext */
  31. /** @typedef {import("./StatsPrinter").StatsPrinterContextWithExtra} StatsPrinterContextWithExtra */
  32. const DATA_URI_CONTENT_LENGTH = 16;
  33. const MAX_MODULE_IDENTIFIER_LENGTH = 80;
  34. /**
  35. * Returns if n is 1, singular, else plural.
  36. * @param {number} n a number
  37. * @param {string} singular singular
  38. * @param {string} plural plural
  39. * @returns {string} if n is 1, singular, else plural
  40. */
  41. const plural = (n, singular, plural) => (n === 1 ? singular : plural);
  42. /**
  43. * Returns text.
  44. * @param {Record<string, number>} sizes sizes by source type
  45. * @param {StatsPrinterContext} options options
  46. * @returns {string | undefined} text
  47. */
  48. const printSizes = (sizes, { formatSize = (n) => `${n}` }) => {
  49. const keys = Object.keys(sizes);
  50. if (keys.length > 1) {
  51. return keys.map((key) => `${formatSize(sizes[key])} (${key})`).join(" ");
  52. } else if (keys.length === 1) {
  53. return formatSize(sizes[keys[0]]);
  54. }
  55. };
  56. /**
  57. * Gets resource name.
  58. * @param {string | null} resource resource
  59. * @returns {string} resource name for display
  60. */
  61. const getResourceName = (resource) => {
  62. if (!resource) return "";
  63. const dataUrl = /^data:[^,]+,/.exec(resource);
  64. if (!dataUrl) return resource;
  65. const len = dataUrl[0].length + DATA_URI_CONTENT_LENGTH;
  66. if (resource.length < len) return resource;
  67. return `${resource.slice(
  68. 0,
  69. Math.min(resource.length - /* '..'.length */ 2, len)
  70. )}..`;
  71. };
  72. /**
  73. * Returns prefix and module name.
  74. * @param {string} name module name
  75. * @returns {[string, string]} prefix and module name
  76. */
  77. const getModuleName = (name) => {
  78. const [, prefix, resource] =
  79. /** @type {[string, string, string]} */
  80. (/** @type {unknown} */ (/^(.*!)?([^!]*)$/.exec(name)));
  81. if (resource.length > MAX_MODULE_IDENTIFIER_LENGTH) {
  82. const truncatedResource = `${resource.slice(
  83. 0,
  84. Math.min(
  85. resource.length - /* '...(truncated)'.length */ 14,
  86. MAX_MODULE_IDENTIFIER_LENGTH
  87. )
  88. )}...(truncated)`;
  89. return [prefix, getResourceName(truncatedResource)];
  90. }
  91. return [prefix, getResourceName(resource)];
  92. };
  93. /**
  94. * Returns joined string.
  95. * @param {string} str string
  96. * @param {(item: string) => string} fn function to apply to each line
  97. * @returns {string} joined string
  98. */
  99. const mapLines = (str, fn) => str.split("\n").map(fn).join("\n");
  100. /**
  101. * Returns number as two digit string, leading 0.
  102. * @param {number} n a number
  103. * @returns {string} number as two digit string, leading 0
  104. */
  105. const twoDigit = (n) => (n >= 10 ? `${n}` : `0${n}`);
  106. /**
  107. * Checks whether this object is valid id.
  108. * @param {string | number | null} id an id
  109. * @returns {id is string | number} is i
  110. */
  111. const isValidId = (id) => {
  112. if (typeof id === "number" || id) {
  113. return true;
  114. }
  115. return false;
  116. };
  117. /**
  118. * Returns string representation of list.
  119. * @template T
  120. * @param {T[] | undefined} list of items
  121. * @param {number} count number of items to show
  122. * @returns {string} string representation of list
  123. */
  124. const moreCount = (list, count) =>
  125. list && list.length > 0 ? `+ ${count}` : `${count}`;
  126. /**
  127. * Defines the with required type used by this module.
  128. * @template T
  129. * @template {keyof T} K
  130. * @typedef {{ [P in K]-?: T[P] }} WithRequired
  131. */
  132. /**
  133. * Defines the define stats printer context type used by this module.
  134. * @template {keyof StatsPrinterContext} RequiredStatsPrinterContextKeys
  135. * @typedef {StatsPrinterContextWithExtra & WithRequired<StatsPrinterContext, "compilation" | RequiredStatsPrinterContextKeys>} DefineStatsPrinterContext
  136. */
  137. /**
  138. * Defines the simple printer type used by this module.
  139. * @template T
  140. * @template {keyof StatsPrinterContext} RequiredStatsPrinterContextKeys
  141. * @typedef {(thing: Exclude<T, undefined>, context: DefineStatsPrinterContext<RequiredStatsPrinterContextKeys>, printer: StatsPrinter) => string | undefined} SimplePrinter
  142. */
  143. /**
  144. * Defines the unpacked type used by this module.
  145. * @template T
  146. * @typedef {T extends (infer U)[] ? U : T} Unpacked
  147. */
  148. /**
  149. * Defines the property name type used by this module.
  150. * @template {object} O
  151. * @template {keyof O} K
  152. * @template {string} B
  153. * @typedef {K extends string ? `${B}.${K}` : never} PropertyName
  154. */
  155. /**
  156. * Defines the array property name type used by this module.
  157. * @template {object} O
  158. * @template {keyof O} K
  159. * @template {string} B
  160. * @typedef {K extends string ? `${B}.${K}[]` : never} ArrayPropertyName
  161. */
  162. /**
  163. * Defines the exclamation type used by this module.
  164. * @template {object} O
  165. * @template {string} K
  166. * @template {string} E
  167. * @typedef {{ [property in `${K}!`]?: SimplePrinter<O, "compilation" | E> }} Exclamation
  168. */
  169. /**
  170. * Defines the shared type used by this module.
  171. * @template {object} O
  172. * @template {string} B
  173. * @template {string} [R=B]
  174. * @typedef {{ [K in keyof O as PropertyName<O, K, B>]?: SimplePrinter<O[K], R> } &
  175. * { [K in keyof O as ArrayPropertyName<O, K, B>]?: Exclude<O[K], undefined> extends (infer I)[] ? SimplePrinter<I, R> : never }} Printers
  176. */
  177. /**
  178. * Defines the shared type used by this module.
  179. * @typedef {Printers<KnownStatsCompilation, "compilation"> &
  180. * { ["compilation.summary!"]?: SimplePrinter<KnownStatsCompilation, "compilation"> } &
  181. * { ["compilation.errorsInChildren!"]?: SimplePrinter<KnownStatsCompilation, "compilation"> } &
  182. * { ["compilation.warningsInChildren!"]?: SimplePrinter<KnownStatsCompilation, "compilation"> }} CompilationSimplePrinters
  183. */
  184. /**
  185. * @type {CompilationSimplePrinters}
  186. */
  187. const COMPILATION_SIMPLE_PRINTERS = {
  188. "compilation.summary!": (
  189. _,
  190. {
  191. type,
  192. bold,
  193. green,
  194. red,
  195. yellow,
  196. formatDateTime,
  197. formatTime,
  198. compilation: {
  199. name,
  200. hash,
  201. version,
  202. time,
  203. builtAt,
  204. errorsCount,
  205. warningsCount
  206. }
  207. }
  208. ) => {
  209. const root = type === "compilation.summary!";
  210. const warningsMessage =
  211. /** @type {number} */ (warningsCount) > 0
  212. ? yellow(
  213. `${warningsCount} ${plural(/** @type {number} */ (warningsCount), "warning", "warnings")}`
  214. )
  215. : "";
  216. const errorsMessage =
  217. /** @type {number} */ (errorsCount) > 0
  218. ? red(
  219. `${errorsCount} ${plural(/** @type {number} */ (errorsCount), "error", "errors")}`
  220. )
  221. : "";
  222. const timeMessage = root && time ? ` in ${formatTime(time)}` : "";
  223. const hashMessage = hash ? ` (${hash})` : "";
  224. const builtAtMessage =
  225. root && builtAt ? `${formatDateTime(builtAt)}: ` : "";
  226. const versionMessage = root && version ? `webpack ${version}` : "";
  227. const nameMessage =
  228. root && name
  229. ? bold(name)
  230. : name
  231. ? `Child ${bold(name)}`
  232. : root
  233. ? ""
  234. : "Child";
  235. const subjectMessage =
  236. nameMessage && versionMessage
  237. ? `${nameMessage} (${versionMessage})`
  238. : versionMessage || nameMessage || "webpack";
  239. /** @type {string} */
  240. let statusMessage;
  241. if (errorsMessage && warningsMessage) {
  242. statusMessage = `compiled with ${errorsMessage} and ${warningsMessage}`;
  243. } else if (errorsMessage) {
  244. statusMessage = `compiled with ${errorsMessage}`;
  245. } else if (warningsMessage) {
  246. statusMessage = `compiled with ${warningsMessage}`;
  247. } else if (errorsCount === 0 && warningsCount === 0) {
  248. statusMessage = `compiled ${green("successfully")}`;
  249. } else {
  250. statusMessage = "compiled";
  251. }
  252. if (
  253. builtAtMessage ||
  254. versionMessage ||
  255. errorsMessage ||
  256. warningsMessage ||
  257. (errorsCount === 0 && warningsCount === 0) ||
  258. timeMessage ||
  259. hashMessage
  260. ) {
  261. return `${builtAtMessage}${subjectMessage} ${statusMessage}${timeMessage}${hashMessage}`;
  262. }
  263. },
  264. "compilation.filteredWarningDetailsCount": (count) =>
  265. count
  266. ? `${count} ${plural(
  267. count,
  268. "warning has",
  269. "warnings have"
  270. )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
  271. : undefined,
  272. "compilation.filteredErrorDetailsCount": (count, { yellow }) =>
  273. count
  274. ? yellow(
  275. `${count} ${plural(
  276. count,
  277. "error has",
  278. "errors have"
  279. )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
  280. )
  281. : undefined,
  282. "compilation.env": (env, { bold }) =>
  283. env
  284. ? `Environment (--env): ${bold(JSON.stringify(env, null, 2))}`
  285. : undefined,
  286. "compilation.publicPath": (publicPath, { bold }) =>
  287. `PublicPath: ${bold(publicPath || "(none)")}`,
  288. "compilation.entrypoints": (entrypoints, context, printer) =>
  289. Array.isArray(entrypoints)
  290. ? undefined
  291. : printer.print(context.type, Object.values(entrypoints), {
  292. ...context,
  293. chunkGroupKind: "Entrypoint"
  294. }),
  295. "compilation.namedChunkGroups": (namedChunkGroups, context, printer) => {
  296. if (!Array.isArray(namedChunkGroups)) {
  297. const {
  298. compilation: { entrypoints }
  299. } = context;
  300. let chunkGroups = Object.values(namedChunkGroups);
  301. if (entrypoints) {
  302. chunkGroups = chunkGroups.filter(
  303. (group) =>
  304. !Object.prototype.hasOwnProperty.call(
  305. entrypoints,
  306. /** @type {string} */
  307. (group.name)
  308. )
  309. );
  310. }
  311. return printer.print(context.type, chunkGroups, {
  312. ...context,
  313. chunkGroupKind: "Chunk Group"
  314. });
  315. }
  316. },
  317. "compilation.assetsByChunkName": () => "",
  318. "compilation.filteredModules": (
  319. filteredModules,
  320. { compilation: { modules } }
  321. ) =>
  322. filteredModules > 0
  323. ? `${moreCount(modules, filteredModules)} ${plural(
  324. filteredModules,
  325. "module",
  326. "modules"
  327. )}`
  328. : undefined,
  329. "compilation.filteredAssets": (
  330. filteredAssets,
  331. { compilation: { assets } }
  332. ) =>
  333. filteredAssets > 0
  334. ? `${moreCount(assets, filteredAssets)} ${plural(
  335. filteredAssets,
  336. "asset",
  337. "assets"
  338. )}`
  339. : undefined,
  340. "compilation.logging": (logging, context, printer) =>
  341. Array.isArray(logging)
  342. ? undefined
  343. : printer.print(
  344. context.type,
  345. Object.entries(logging).map(([name, value]) => ({ ...value, name })),
  346. context
  347. ),
  348. "compilation.warningsInChildren!": (_, { yellow, compilation }) => {
  349. if (
  350. !compilation.children &&
  351. /** @type {number} */ (compilation.warningsCount) > 0 &&
  352. compilation.warnings
  353. ) {
  354. const childWarnings =
  355. /** @type {number} */ (compilation.warningsCount) -
  356. compilation.warnings.length;
  357. if (childWarnings > 0) {
  358. return yellow(
  359. `${childWarnings} ${plural(
  360. childWarnings,
  361. "WARNING",
  362. "WARNINGS"
  363. )} in child compilations${
  364. compilation.children
  365. ? ""
  366. : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
  367. }`
  368. );
  369. }
  370. }
  371. },
  372. "compilation.errorsInChildren!": (_, { red, compilation }) => {
  373. if (
  374. !compilation.children &&
  375. /** @type {number} */ (compilation.errorsCount) > 0 &&
  376. compilation.errors
  377. ) {
  378. const childErrors =
  379. /** @type {number} */ (compilation.errorsCount) -
  380. compilation.errors.length;
  381. if (childErrors > 0) {
  382. return red(
  383. `${childErrors} ${plural(
  384. childErrors,
  385. "ERROR",
  386. "ERRORS"
  387. )} in child compilations${
  388. compilation.children
  389. ? ""
  390. : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
  391. }`
  392. );
  393. }
  394. }
  395. }
  396. };
  397. /**
  398. * Defines the shared type used by this module.
  399. * @typedef {Printers<KnownStatsAsset, "asset"> &
  400. * Printers<KnownStatsAsset["info"], "asset.info"> &
  401. * Exclamation<KnownStatsAsset, "asset.separator", "asset"> &
  402. * { ["asset.filteredChildren"]?: SimplePrinter<number, "asset"> } &
  403. * { assetChunk?: SimplePrinter<ChunkId, "asset"> } &
  404. * { assetChunkName?: SimplePrinter<ChunkName, "asset"> } &
  405. * { assetChunkIdHint?: SimplePrinter<string, "asset"> }} AssetSimplePrinters
  406. */
  407. /** @type {AssetSimplePrinters} */
  408. const ASSET_SIMPLE_PRINTERS = {
  409. "asset.type": (type) => type,
  410. "asset.name": (name, { formatFilename, asset: { isOverSizeLimit } }) =>
  411. formatFilename(name, isOverSizeLimit),
  412. "asset.size": (size, { asset: { isOverSizeLimit }, yellow, formatSize }) =>
  413. isOverSizeLimit ? yellow(formatSize(size)) : formatSize(size),
  414. "asset.emitted": (emitted, { green, formatFlag }) =>
  415. emitted ? green(formatFlag("emitted")) : undefined,
  416. "asset.comparedForEmit": (comparedForEmit, { yellow, formatFlag }) =>
  417. comparedForEmit ? yellow(formatFlag("compared for emit")) : undefined,
  418. "asset.cached": (cached, { green, formatFlag }) =>
  419. cached ? green(formatFlag("cached")) : undefined,
  420. "asset.isOverSizeLimit": (isOverSizeLimit, { yellow, formatFlag }) =>
  421. isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
  422. "asset.info.immutable": (immutable, { green, formatFlag }) =>
  423. immutable ? green(formatFlag("immutable")) : undefined,
  424. "asset.info.javascriptModule": (javascriptModule, { formatFlag }) =>
  425. javascriptModule ? formatFlag("javascript module") : undefined,
  426. "asset.info.sourceFilename": (sourceFilename, { formatFlag }) =>
  427. sourceFilename ? formatFlag(`from: ${sourceFilename}`) : undefined,
  428. "asset.info.development": (development, { green, formatFlag }) =>
  429. development ? green(formatFlag("dev")) : undefined,
  430. "asset.info.hotModuleReplacement": (
  431. hotModuleReplacement,
  432. { green, formatFlag }
  433. ) => (hotModuleReplacement ? green(formatFlag("hmr")) : undefined),
  434. "asset.separator!": () => "\n",
  435. "asset.filteredRelated": (filteredRelated, { asset: { related } }) =>
  436. filteredRelated > 0
  437. ? `${moreCount(related, filteredRelated)} related ${plural(
  438. filteredRelated,
  439. "asset",
  440. "assets"
  441. )}`
  442. : undefined,
  443. "asset.filteredChildren": (filteredChildren, { asset: { children } }) =>
  444. filteredChildren > 0
  445. ? `${moreCount(children, filteredChildren)} ${plural(
  446. filteredChildren,
  447. "asset",
  448. "assets"
  449. )}`
  450. : undefined,
  451. assetChunk: (id, { formatChunkId }) => formatChunkId(id),
  452. assetChunkName: (name) => name || undefined,
  453. assetChunkIdHint: (name) => name || undefined
  454. };
  455. /**
  456. * Defines the shared type used by this module.
  457. * @typedef {Printers<KnownStatsModule, "module"> &
  458. * Exclamation<KnownStatsModule, "module.separator", "module"> &
  459. * { ["module.filteredChildren"]?: SimplePrinter<number, "module"> } &
  460. * { ["module.filteredReasons"]?: SimplePrinter<number, "module"> }} ModuleSimplePrinters
  461. */
  462. /** @type {ModuleSimplePrinters} */
  463. const MODULE_SIMPLE_PRINTERS = {
  464. "module.type": (type) => (type !== "module" ? type : undefined),
  465. "module.id": (id, { formatModuleId }) =>
  466. isValidId(id) ? formatModuleId(id) : undefined,
  467. "module.name": (name, { bold }) => {
  468. const [prefix, resource] = getModuleName(name);
  469. return `${prefix || ""}${bold(resource || "")}`;
  470. },
  471. "module.identifier": (_identifier) => undefined,
  472. "module.layer": (layer, { formatLayer }) =>
  473. layer ? formatLayer(layer) : undefined,
  474. "module.sizes": printSizes,
  475. "module.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
  476. "module.depth": (depth, { formatFlag }) =>
  477. depth !== null ? formatFlag(`depth ${depth}`) : undefined,
  478. "module.cacheable": (cacheable, { formatFlag, red }) =>
  479. cacheable === false ? red(formatFlag("not cacheable")) : undefined,
  480. "module.orphan": (orphan, { formatFlag, yellow }) =>
  481. orphan ? yellow(formatFlag("orphan")) : undefined,
  482. // "module.runtime": (runtime, { formatFlag, yellow }) =>
  483. // runtime ? yellow(formatFlag("runtime")) : undefined,
  484. "module.optional": (optional, { formatFlag, yellow }) =>
  485. optional ? yellow(formatFlag("optional")) : undefined,
  486. "module.dependent": (dependent, { formatFlag, cyan }) =>
  487. dependent ? cyan(formatFlag("dependent")) : undefined,
  488. "module.built": (built, { formatFlag, yellow }) =>
  489. built ? yellow(formatFlag("built")) : undefined,
  490. "module.codeGenerated": (codeGenerated, { formatFlag, yellow }) =>
  491. codeGenerated ? yellow(formatFlag("code generated")) : undefined,
  492. "module.buildTimeExecuted": (buildTimeExecuted, { formatFlag, green }) =>
  493. buildTimeExecuted ? green(formatFlag("build time executed")) : undefined,
  494. "module.cached": (cached, { formatFlag, green }) =>
  495. cached ? green(formatFlag("cached")) : undefined,
  496. "module.assets": (assets, { formatFlag, magenta }) =>
  497. assets && assets.length
  498. ? magenta(
  499. formatFlag(
  500. `${assets.length} ${plural(assets.length, "asset", "assets")}`
  501. )
  502. )
  503. : undefined,
  504. "module.warnings": (warnings, { formatFlag, yellow }) =>
  505. warnings
  506. ? yellow(
  507. formatFlag(`${warnings} ${plural(warnings, "warning", "warnings")}`)
  508. )
  509. : undefined,
  510. "module.errors": (errors, { formatFlag, red }) =>
  511. errors
  512. ? red(formatFlag(`${errors} ${plural(errors, "error", "errors")}`))
  513. : undefined,
  514. "module.providedExports": (providedExports, { formatFlag, cyan }) => {
  515. if (Array.isArray(providedExports)) {
  516. if (providedExports.length === 0) return cyan(formatFlag("no exports"));
  517. return cyan(formatFlag(`exports: ${providedExports.join(", ")}`));
  518. }
  519. },
  520. "module.usedExports": (usedExports, { formatFlag, cyan, module }) => {
  521. if (usedExports !== true) {
  522. if (usedExports === null) return cyan(formatFlag("used exports unknown"));
  523. if (usedExports === false) return cyan(formatFlag("module unused"));
  524. if (Array.isArray(usedExports)) {
  525. if (usedExports.length === 0) {
  526. return cyan(formatFlag("no exports used"));
  527. }
  528. const providedExportsCount = Array.isArray(module.providedExports)
  529. ? module.providedExports.length
  530. : null;
  531. if (
  532. providedExportsCount !== null &&
  533. providedExportsCount === usedExports.length
  534. ) {
  535. return cyan(formatFlag("all exports used"));
  536. }
  537. return cyan(
  538. formatFlag(`only some exports used: ${usedExports.join(", ")}`)
  539. );
  540. }
  541. }
  542. },
  543. "module.optimizationBailout[]": (optimizationBailout, { yellow }) =>
  544. yellow(optimizationBailout),
  545. "module.issuerPath": (issuerPath, { module }) =>
  546. module.profile ? undefined : "",
  547. "module.profile": (_profile) => undefined,
  548. "module.filteredModules": (filteredModules, { module: { modules } }) =>
  549. filteredModules > 0
  550. ? `${moreCount(modules, filteredModules)} nested ${plural(
  551. filteredModules,
  552. "module",
  553. "modules"
  554. )}`
  555. : undefined,
  556. "module.filteredReasons": (filteredReasons, { module: { reasons } }) =>
  557. filteredReasons > 0
  558. ? `${moreCount(reasons, filteredReasons)} ${plural(
  559. filteredReasons,
  560. "reason",
  561. "reasons"
  562. )}`
  563. : undefined,
  564. "module.filteredChildren": (filteredChildren, { module: { children } }) =>
  565. filteredChildren > 0
  566. ? `${moreCount(children, filteredChildren)} ${plural(
  567. filteredChildren,
  568. "module",
  569. "modules"
  570. )}`
  571. : undefined,
  572. "module.separator!": () => "\n"
  573. };
  574. /**
  575. * Defines the module issuer printers type used by this module.
  576. * @typedef {Printers<KnownStatsModuleIssuer, "moduleIssuer"> & Printers<KnownStatsModuleIssuer["profile"], "moduleIssuer.profile", "moduleIssuer">} ModuleIssuerPrinters
  577. */
  578. /** @type {ModuleIssuerPrinters} */
  579. const MODULE_ISSUER_PRINTERS = {
  580. "moduleIssuer.id": (id, { formatModuleId }) => formatModuleId(id),
  581. "moduleIssuer.profile.total": (value, { formatTime }) => formatTime(value)
  582. };
  583. /**
  584. * Defines the module reasons printers type used by this module.
  585. * @typedef {Printers<KnownStatsModuleReason, "moduleReason"> & { ["moduleReason.filteredChildren"]?: SimplePrinter<number, "moduleReason"> }} ModuleReasonsPrinters
  586. */
  587. /** @type {ModuleReasonsPrinters} */
  588. const MODULE_REASON_PRINTERS = {
  589. "moduleReason.type": (type) => type || undefined,
  590. "moduleReason.userRequest": (userRequest, { cyan }) =>
  591. cyan(getResourceName(userRequest)),
  592. "moduleReason.moduleId": (moduleId, { formatModuleId }) =>
  593. isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
  594. "moduleReason.module": (module, { magenta }) =>
  595. module ? magenta(module) : undefined,
  596. "moduleReason.loc": (loc) => loc || undefined,
  597. "moduleReason.explanation": (explanation, { cyan }) =>
  598. explanation ? cyan(explanation) : undefined,
  599. "moduleReason.active": (active, { formatFlag }) =>
  600. active ? undefined : formatFlag("inactive"),
  601. "moduleReason.resolvedModule": (module, { magenta }) =>
  602. module ? magenta(module) : undefined,
  603. "moduleReason.filteredChildren": (
  604. filteredChildren,
  605. { moduleReason: { children } }
  606. ) =>
  607. filteredChildren > 0
  608. ? `${moreCount(children, filteredChildren)} ${plural(
  609. filteredChildren,
  610. "reason",
  611. "reasons"
  612. )}`
  613. : undefined
  614. };
  615. /** @typedef {Printers<KnownStatsProfile, "module.profile", "profile">} ModuleProfilePrinters */
  616. /** @type {ModuleProfilePrinters} */
  617. const MODULE_PROFILE_PRINTERS = {
  618. "module.profile.total": (value, { formatTime }) => formatTime(value),
  619. "module.profile.resolving": (value, { formatTime }) =>
  620. `resolving: ${formatTime(value)}`,
  621. "module.profile.restoring": (value, { formatTime }) =>
  622. `restoring: ${formatTime(value)}`,
  623. "module.profile.integration": (value, { formatTime }) =>
  624. `integration: ${formatTime(value)}`,
  625. "module.profile.building": (value, { formatTime }) =>
  626. `building: ${formatTime(value)}`,
  627. "module.profile.storing": (value, { formatTime }) =>
  628. `storing: ${formatTime(value)}`,
  629. "module.profile.additionalResolving": (value, { formatTime }) =>
  630. value ? `additional resolving: ${formatTime(value)}` : undefined,
  631. "module.profile.additionalIntegration": (value, { formatTime }) =>
  632. value ? `additional integration: ${formatTime(value)}` : undefined
  633. };
  634. /**
  635. * Defines the shared type used by this module.
  636. * @typedef {Exclamation<KnownStatsChunkGroup, "chunkGroup.kind", "chunkGroupKind"> &
  637. * Exclamation<KnownStatsChunkGroup, "chunkGroup.separator", "chunkGroup"> &
  638. * Printers<KnownStatsChunkGroup, "chunkGroup"> &
  639. * Exclamation<KnownStatsChunkGroup, "chunkGroup.is", "chunkGroup"> &
  640. * Printers<Exclude<KnownStatsChunkGroup["assets"], undefined>[number], "chunkGroupAsset" | "chunkGroup"> &
  641. * { ['chunkGroupChildGroup.type']?: SimplePrinter<string, "chunkGroupAsset"> } &
  642. * { ['chunkGroupChild.assets[]']?: SimplePrinter<string, "chunkGroupAsset"> } &
  643. * { ['chunkGroupChild.chunks[]']?: SimplePrinter<ChunkId, "chunkGroupAsset"> } &
  644. * { ['chunkGroupChild.name']?: SimplePrinter<ChunkName, "chunkGroupAsset"> }} ChunkGroupPrinters
  645. */
  646. /** @type {ChunkGroupPrinters} */
  647. const CHUNK_GROUP_PRINTERS = {
  648. "chunkGroup.kind!": (_, { chunkGroupKind }) => chunkGroupKind,
  649. "chunkGroup.separator!": () => "\n",
  650. "chunkGroup.name": (name, { bold }) => (name ? bold(name) : undefined),
  651. "chunkGroup.isOverSizeLimit": (isOverSizeLimit, { formatFlag, yellow }) =>
  652. isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
  653. "chunkGroup.assetsSize": (size, { formatSize }) =>
  654. size ? formatSize(size) : undefined,
  655. "chunkGroup.auxiliaryAssetsSize": (size, { formatSize }) =>
  656. size ? `(${formatSize(size)})` : undefined,
  657. "chunkGroup.filteredAssets": (n, { chunkGroup: { assets } }) =>
  658. n > 0
  659. ? `${moreCount(assets, n)} ${plural(n, "asset", "assets")}`
  660. : undefined,
  661. "chunkGroup.filteredAuxiliaryAssets": (
  662. n,
  663. { chunkGroup: { auxiliaryAssets } }
  664. ) =>
  665. n > 0
  666. ? `${moreCount(auxiliaryAssets, n)} auxiliary ${plural(
  667. n,
  668. "asset",
  669. "assets"
  670. )}`
  671. : undefined,
  672. "chunkGroup.is!": () => "=",
  673. "chunkGroupAsset.name": (asset, { green }) => green(asset),
  674. "chunkGroupAsset.size": (size, { formatSize, chunkGroup }) =>
  675. chunkGroup.assets &&
  676. (chunkGroup.assets.length > 1 ||
  677. (chunkGroup.auxiliaryAssets && chunkGroup.auxiliaryAssets.length > 0)
  678. ? formatSize(size)
  679. : undefined),
  680. "chunkGroup.children": (children, context, printer) =>
  681. Array.isArray(children)
  682. ? undefined
  683. : printer.print(
  684. context.type,
  685. Object.keys(children).map((key) => ({
  686. type: key,
  687. children: children[key]
  688. })),
  689. context
  690. ),
  691. "chunkGroupChildGroup.type": (type) => `${type}:`,
  692. "chunkGroupChild.assets[]": (file, { formatFilename }) =>
  693. formatFilename(file),
  694. "chunkGroupChild.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
  695. "chunkGroupChild.name": (name) => (name ? `(name: ${name})` : undefined)
  696. };
  697. /**
  698. * Defines the shared type used by this module.
  699. * @typedef {Printers<KnownStatsChunk, "chunk"> &
  700. * { ["chunk.childrenByOrder[].type"]: SimplePrinter<string, "chunk"> } &
  701. * { ["chunk.childrenByOrder[].children[]"]: SimplePrinter<ChunkId, "chunk"> } &
  702. * Exclamation<KnownStatsChunk, "chunk.separator", "chunk"> &
  703. * Printers<KnownStatsChunkOrigin, "chunkOrigin">} ChunkPrinters
  704. */
  705. /** @type {ChunkPrinters} */
  706. const CHUNK_PRINTERS = {
  707. "chunk.id": (id, { formatChunkId }) => formatChunkId(id),
  708. "chunk.files[]": (file, { formatFilename }) => formatFilename(file),
  709. "chunk.names[]": (name) => name,
  710. "chunk.idHints[]": (name) => name,
  711. "chunk.runtime[]": (name) => name,
  712. "chunk.sizes": (sizes, context) => printSizes(sizes, context),
  713. "chunk.parents[]": (parents, context) =>
  714. context.formatChunkId(parents, "parent"),
  715. "chunk.siblings[]": (siblings, context) =>
  716. context.formatChunkId(siblings, "sibling"),
  717. "chunk.children[]": (children, context) =>
  718. context.formatChunkId(children, "child"),
  719. "chunk.childrenByOrder": (childrenByOrder, context, printer) =>
  720. Array.isArray(childrenByOrder)
  721. ? undefined
  722. : printer.print(
  723. context.type,
  724. Object.keys(childrenByOrder).map((key) => ({
  725. type: key,
  726. children: childrenByOrder[key]
  727. })),
  728. context
  729. ),
  730. "chunk.childrenByOrder[].type": (type) => `${type}:`,
  731. "chunk.childrenByOrder[].children[]": (id, { formatChunkId }) =>
  732. isValidId(id) ? formatChunkId(id) : undefined,
  733. "chunk.entry": (entry, { formatFlag, yellow }) =>
  734. entry ? yellow(formatFlag("entry")) : undefined,
  735. "chunk.initial": (initial, { formatFlag, yellow }) =>
  736. initial ? yellow(formatFlag("initial")) : undefined,
  737. "chunk.rendered": (rendered, { formatFlag, green }) =>
  738. rendered ? green(formatFlag("rendered")) : undefined,
  739. "chunk.recorded": (recorded, { formatFlag, green }) =>
  740. recorded ? green(formatFlag("recorded")) : undefined,
  741. "chunk.reason": (reason, { yellow }) => (reason ? yellow(reason) : undefined),
  742. "chunk.filteredModules": (filteredModules, { chunk: { modules } }) =>
  743. filteredModules > 0
  744. ? `${moreCount(modules, filteredModules)} chunk ${plural(
  745. filteredModules,
  746. "module",
  747. "modules"
  748. )}`
  749. : undefined,
  750. "chunk.separator!": () => "\n",
  751. "chunkOrigin.request": (request) => request,
  752. "chunkOrigin.moduleId": (moduleId, { formatModuleId }) =>
  753. isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
  754. "chunkOrigin.moduleName": (moduleName, { bold }) => bold(moduleName),
  755. "chunkOrigin.loc": (loc) => loc
  756. };
  757. /**
  758. * Defines the shared type used by this module.
  759. * @typedef {Printers<KnownStatsError, "error"> &
  760. * { ["error.filteredDetails"]?: SimplePrinter<number, "error"> } &
  761. * Exclamation<KnownStatsError, "error.separator", "error">} ErrorPrinters
  762. */
  763. /**
  764. * @type {ErrorPrinters}
  765. */
  766. const ERROR_PRINTERS = {
  767. "error.compilerPath": (compilerPath, { bold }) =>
  768. compilerPath ? bold(`(${compilerPath})`) : undefined,
  769. "error.chunkId": (chunkId, { formatChunkId }) =>
  770. isValidId(chunkId) ? formatChunkId(chunkId) : undefined,
  771. "error.chunkEntry": (chunkEntry, { formatFlag }) =>
  772. chunkEntry ? formatFlag("entry") : undefined,
  773. "error.chunkInitial": (chunkInitial, { formatFlag }) =>
  774. chunkInitial ? formatFlag("initial") : undefined,
  775. "error.file": (file, { bold }) => bold(file),
  776. "error.moduleName": (moduleName, { bold }) =>
  777. moduleName.includes("!")
  778. ? `${bold(moduleName.replace(/^([\s\S])*!/, ""))} (${moduleName})`
  779. : `${bold(moduleName)}`,
  780. "error.loc": (loc, { green }) => green(loc),
  781. "error.message": (message, { bold, formatError }) =>
  782. message.includes("\u001B[") ? message : bold(formatError(message)),
  783. "error.details": (details, { formatError }) => formatError(details),
  784. "error.filteredDetails": (filteredDetails) =>
  785. filteredDetails ? `+ ${filteredDetails} hidden lines` : undefined,
  786. "error.stack": (stack) => stack,
  787. "error.cause": (cause, context, printer) =>
  788. cause
  789. ? indent(
  790. `[cause]: ${
  791. /** @type {string} */
  792. (printer.print(`${context.type}.error`, cause, context))
  793. }`,
  794. " "
  795. )
  796. : undefined,
  797. "error.moduleTrace": (_moduleTrace) => undefined,
  798. "error.separator!": () => "\n"
  799. };
  800. /**
  801. * Defines the shared type used by this module.
  802. * @typedef {Printers<KnownStatsLoggingEntry, `loggingEntry(${LogTypeEnum}).loggingEntry`> &
  803. * { ["loggingEntry(clear).loggingEntry"]?: SimplePrinter<KnownStatsLoggingEntry, "logging"> } &
  804. * { ["loggingEntry.trace[]"]?: SimplePrinter<Exclude<KnownStatsLoggingEntry["trace"], undefined>[number], "logging"> } &
  805. * { loggingGroup?: SimplePrinter<KnownStatsLogging[], "logging"> } &
  806. * Printers<KnownStatsLogging & { name: string }, `loggingGroup`> &
  807. * Exclamation<KnownStatsLogging, "loggingGroup.separator", "loggingGroup">} LogEntryPrinters
  808. */
  809. /** @type {LogEntryPrinters} */
  810. const LOG_ENTRY_PRINTERS = {
  811. "loggingEntry(error).loggingEntry.message": (message, { red }) =>
  812. mapLines(message, (x) => `<e> ${red(x)}`),
  813. "loggingEntry(warn).loggingEntry.message": (message, { yellow }) =>
  814. mapLines(message, (x) => `<w> ${yellow(x)}`),
  815. "loggingEntry(info).loggingEntry.message": (message, { green }) =>
  816. mapLines(message, (x) => `<i> ${green(x)}`),
  817. "loggingEntry(log).loggingEntry.message": (message, { bold }) =>
  818. mapLines(message, (x) => ` ${bold(x)}`),
  819. "loggingEntry(debug).loggingEntry.message": (message) =>
  820. mapLines(message, (x) => ` ${x}`),
  821. "loggingEntry(trace).loggingEntry.message": (message) =>
  822. mapLines(message, (x) => ` ${x}`),
  823. "loggingEntry(status).loggingEntry.message": (message, { magenta }) =>
  824. mapLines(message, (x) => `<s> ${magenta(x)}`),
  825. "loggingEntry(profile).loggingEntry.message": (message, { magenta }) =>
  826. mapLines(message, (x) => `<p> ${magenta(x)}`),
  827. "loggingEntry(profileEnd).loggingEntry.message": (message, { magenta }) =>
  828. mapLines(message, (x) => `</p> ${magenta(x)}`),
  829. "loggingEntry(time).loggingEntry.message": (message, { magenta }) =>
  830. mapLines(message, (x) => `<t> ${magenta(x)}`),
  831. "loggingEntry(group).loggingEntry.message": (message, { cyan }) =>
  832. mapLines(message, (x) => `<-> ${cyan(x)}`),
  833. "loggingEntry(groupCollapsed).loggingEntry.message": (message, { cyan }) =>
  834. mapLines(message, (x) => `<+> ${cyan(x)}`),
  835. "loggingEntry(clear).loggingEntry": () => " -------",
  836. "loggingEntry(groupCollapsed).loggingEntry.children": () => "",
  837. "loggingEntry.trace[]": (trace) =>
  838. trace ? mapLines(trace, (x) => `| ${x}`) : undefined,
  839. loggingGroup: (loggingGroup) =>
  840. loggingGroup.entries.length === 0 ? "" : undefined,
  841. "loggingGroup.debug": (flag, { red }) => (flag ? red("DEBUG") : undefined),
  842. "loggingGroup.name": (name, { bold }) => bold(`LOG from ${name}`),
  843. "loggingGroup.separator!": () => "\n",
  844. "loggingGroup.filteredEntries": (filteredEntries) =>
  845. filteredEntries > 0 ? `+ ${filteredEntries} hidden lines` : undefined
  846. };
  847. /** @typedef {Printers<KnownStatsModuleTraceItem, "moduleTraceItem">} ModuleTraceItemPrinters */
  848. /** @type {ModuleTraceItemPrinters} */
  849. const MODULE_TRACE_ITEM_PRINTERS = {
  850. "moduleTraceItem.originName": (originName) => originName
  851. };
  852. /** @typedef {Printers<KnownStatsModuleTraceDependency, "moduleTraceDependency">} ModuleTraceDependencyPrinters */
  853. /** @type {ModuleTraceDependencyPrinters} */
  854. const MODULE_TRACE_DEPENDENCY_PRINTERS = {
  855. "moduleTraceDependency.loc": (loc) => loc
  856. };
  857. /**
  858. * @type {Record<string, string | ((item: KnownStatsLoggingEntry) => string)>}
  859. */
  860. const ITEM_NAMES = {
  861. "compilation.assets[]": "asset",
  862. "compilation.modules[]": "module",
  863. "compilation.chunks[]": "chunk",
  864. "compilation.entrypoints[]": "chunkGroup",
  865. "compilation.namedChunkGroups[]": "chunkGroup",
  866. "compilation.errors[]": "error",
  867. "compilation.warnings[]": "error",
  868. "compilation.logging[]": "loggingGroup",
  869. "compilation.children[]": "compilation",
  870. "asset.related[]": "asset",
  871. "asset.children[]": "asset",
  872. "asset.chunks[]": "assetChunk",
  873. "asset.auxiliaryChunks[]": "assetChunk",
  874. "asset.chunkNames[]": "assetChunkName",
  875. "asset.chunkIdHints[]": "assetChunkIdHint",
  876. "asset.auxiliaryChunkNames[]": "assetChunkName",
  877. "asset.auxiliaryChunkIdHints[]": "assetChunkIdHint",
  878. "chunkGroup.assets[]": "chunkGroupAsset",
  879. "chunkGroup.auxiliaryAssets[]": "chunkGroupAsset",
  880. "chunkGroupChild.assets[]": "chunkGroupAsset",
  881. "chunkGroupChild.auxiliaryAssets[]": "chunkGroupAsset",
  882. "chunkGroup.children[]": "chunkGroupChildGroup",
  883. "chunkGroupChildGroup.children[]": "chunkGroupChild",
  884. "module.modules[]": "module",
  885. "module.children[]": "module",
  886. "module.reasons[]": "moduleReason",
  887. "moduleReason.children[]": "moduleReason",
  888. "module.issuerPath[]": "moduleIssuer",
  889. "chunk.origins[]": "chunkOrigin",
  890. "chunk.modules[]": "module",
  891. "loggingGroup.entries[]": (logEntry) =>
  892. `loggingEntry(${logEntry.type}).loggingEntry`,
  893. "loggingEntry.children[]": (logEntry) =>
  894. `loggingEntry(${logEntry.type}).loggingEntry`,
  895. "error.moduleTrace[]": "moduleTraceItem",
  896. "error.errors[]": "error",
  897. "moduleTraceItem.dependencies[]": "moduleTraceDependency"
  898. };
  899. const ERROR_PREFERRED_ORDER = [
  900. "compilerPath",
  901. "chunkId",
  902. "chunkEntry",
  903. "chunkInitial",
  904. "file",
  905. "separator!",
  906. "moduleName",
  907. "loc",
  908. "separator!",
  909. "message",
  910. "separator!",
  911. "details",
  912. "separator!",
  913. "filteredDetails",
  914. "separator!",
  915. "stack",
  916. "separator!",
  917. "cause",
  918. "separator!",
  919. "missing",
  920. "separator!",
  921. "moduleTrace"
  922. ];
  923. /** @type {Record<string, string[]>} */
  924. const PREFERRED_ORDERS = {
  925. compilation: [
  926. "name",
  927. "hash",
  928. "version",
  929. "time",
  930. "builtAt",
  931. "env",
  932. "publicPath",
  933. "assets",
  934. "filteredAssets",
  935. "entrypoints",
  936. "namedChunkGroups",
  937. "chunks",
  938. "modules",
  939. "filteredModules",
  940. "children",
  941. "logging",
  942. "warnings",
  943. "warningsInChildren!",
  944. "filteredWarningDetailsCount",
  945. "errors",
  946. "errorsInChildren!",
  947. "filteredErrorDetailsCount",
  948. "summary!",
  949. "needAdditionalPass"
  950. ],
  951. asset: [
  952. "type",
  953. "name",
  954. "size",
  955. "chunks",
  956. "auxiliaryChunks",
  957. "emitted",
  958. "comparedForEmit",
  959. "cached",
  960. "info",
  961. "isOverSizeLimit",
  962. "chunkNames",
  963. "auxiliaryChunkNames",
  964. "chunkIdHints",
  965. "auxiliaryChunkIdHints",
  966. "related",
  967. "filteredRelated",
  968. "children",
  969. "filteredChildren"
  970. ],
  971. "asset.info": [
  972. "immutable",
  973. "sourceFilename",
  974. "javascriptModule",
  975. "development",
  976. "hotModuleReplacement"
  977. ],
  978. chunkGroup: [
  979. "kind!",
  980. "name",
  981. "isOverSizeLimit",
  982. "assetsSize",
  983. "auxiliaryAssetsSize",
  984. "is!",
  985. "assets",
  986. "filteredAssets",
  987. "auxiliaryAssets",
  988. "filteredAuxiliaryAssets",
  989. "separator!",
  990. "children"
  991. ],
  992. chunkGroupAsset: ["name", "size"],
  993. chunkGroupChildGroup: ["type", "children"],
  994. chunkGroupChild: ["assets", "chunks", "name"],
  995. module: [
  996. "type",
  997. "name",
  998. "identifier",
  999. "id",
  1000. "layer",
  1001. "sizes",
  1002. "chunks",
  1003. "depth",
  1004. "cacheable",
  1005. "orphan",
  1006. "runtime",
  1007. "optional",
  1008. "dependent",
  1009. "built",
  1010. "codeGenerated",
  1011. "cached",
  1012. "assets",
  1013. "failed",
  1014. "warnings",
  1015. "errors",
  1016. "children",
  1017. "filteredChildren",
  1018. "providedExports",
  1019. "usedExports",
  1020. "optimizationBailout",
  1021. "reasons",
  1022. "filteredReasons",
  1023. "issuerPath",
  1024. "profile",
  1025. "modules",
  1026. "filteredModules"
  1027. ],
  1028. moduleReason: [
  1029. "active",
  1030. "type",
  1031. "userRequest",
  1032. "moduleId",
  1033. "module",
  1034. "resolvedModule",
  1035. "loc",
  1036. "explanation",
  1037. "children",
  1038. "filteredChildren"
  1039. ],
  1040. "module.profile": [
  1041. "total",
  1042. "separator!",
  1043. "resolving",
  1044. "restoring",
  1045. "integration",
  1046. "building",
  1047. "storing",
  1048. "additionalResolving",
  1049. "additionalIntegration"
  1050. ],
  1051. chunk: [
  1052. "id",
  1053. "runtime",
  1054. "files",
  1055. "names",
  1056. "idHints",
  1057. "sizes",
  1058. "parents",
  1059. "siblings",
  1060. "children",
  1061. "childrenByOrder",
  1062. "entry",
  1063. "initial",
  1064. "rendered",
  1065. "recorded",
  1066. "reason",
  1067. "separator!",
  1068. "origins",
  1069. "separator!",
  1070. "modules",
  1071. "separator!",
  1072. "filteredModules"
  1073. ],
  1074. chunkOrigin: ["request", "moduleId", "moduleName", "loc"],
  1075. error: ERROR_PREFERRED_ORDER,
  1076. warning: ERROR_PREFERRED_ORDER,
  1077. "chunk.childrenByOrder[]": ["type", "children"],
  1078. loggingGroup: [
  1079. "debug",
  1080. "name",
  1081. "separator!",
  1082. "entries",
  1083. "separator!",
  1084. "filteredEntries"
  1085. ],
  1086. loggingEntry: ["message", "trace", "children"]
  1087. };
  1088. /** @typedef {(items: string[]) => string | undefined} SimpleItemsJoiner */
  1089. /** @type {SimpleItemsJoiner} */
  1090. const itemsJoinOneLine = (items) => items.filter(Boolean).join(" ");
  1091. /** @type {SimpleItemsJoiner} */
  1092. const itemsJoinOneLineBrackets = (items) =>
  1093. items.length > 0 ? `(${items.filter(Boolean).join(" ")})` : undefined;
  1094. /** @type {SimpleItemsJoiner} */
  1095. const itemsJoinMoreSpacing = (items) => items.filter(Boolean).join("\n\n");
  1096. /** @type {SimpleItemsJoiner} */
  1097. const itemsJoinComma = (items) => items.filter(Boolean).join(", ");
  1098. /** @type {SimpleItemsJoiner} */
  1099. const itemsJoinCommaBrackets = (items) =>
  1100. items.length > 0 ? `(${items.filter(Boolean).join(", ")})` : undefined;
  1101. /** @type {(item: string) => SimpleItemsJoiner} */
  1102. const itemsJoinCommaBracketsWithName = (name) => (items) =>
  1103. items.length > 0
  1104. ? `(${name}: ${items.filter(Boolean).join(", ")})`
  1105. : undefined;
  1106. /** @type {Record<string, SimpleItemsJoiner>} */
  1107. const SIMPLE_ITEMS_JOINER = {
  1108. "chunk.parents": itemsJoinOneLine,
  1109. "chunk.siblings": itemsJoinOneLine,
  1110. "chunk.children": itemsJoinOneLine,
  1111. "chunk.names": itemsJoinCommaBrackets,
  1112. "chunk.idHints": itemsJoinCommaBracketsWithName("id hint"),
  1113. "chunk.runtime": itemsJoinCommaBracketsWithName("runtime"),
  1114. "chunk.files": itemsJoinComma,
  1115. "chunk.childrenByOrder": itemsJoinOneLine,
  1116. "chunk.childrenByOrder[].children": itemsJoinOneLine,
  1117. "chunkGroup.assets": itemsJoinOneLine,
  1118. "chunkGroup.auxiliaryAssets": itemsJoinOneLineBrackets,
  1119. "chunkGroupChildGroup.children": itemsJoinComma,
  1120. "chunkGroupChild.assets": itemsJoinOneLine,
  1121. "chunkGroupChild.auxiliaryAssets": itemsJoinOneLineBrackets,
  1122. "asset.chunks": itemsJoinComma,
  1123. "asset.auxiliaryChunks": itemsJoinCommaBrackets,
  1124. "asset.chunkNames": itemsJoinCommaBracketsWithName("name"),
  1125. "asset.auxiliaryChunkNames": itemsJoinCommaBracketsWithName("auxiliary name"),
  1126. "asset.chunkIdHints": itemsJoinCommaBracketsWithName("id hint"),
  1127. "asset.auxiliaryChunkIdHints":
  1128. itemsJoinCommaBracketsWithName("auxiliary id hint"),
  1129. "module.chunks": itemsJoinOneLine,
  1130. "module.issuerPath": (items) =>
  1131. items
  1132. .filter(Boolean)
  1133. .map((item) => `${item} ->`)
  1134. .join(" "),
  1135. "compilation.errors": itemsJoinMoreSpacing,
  1136. "compilation.warnings": itemsJoinMoreSpacing,
  1137. "compilation.logging": itemsJoinMoreSpacing,
  1138. "compilation.children": (items) =>
  1139. indent(/** @type {string} */ (itemsJoinMoreSpacing(items)), " "),
  1140. "moduleTraceItem.dependencies": itemsJoinOneLine,
  1141. "loggingEntry.children": (items) =>
  1142. indent(items.filter(Boolean).join("\n"), " ", false)
  1143. };
  1144. /**
  1145. * Returns result.
  1146. * @param {Item[]} items items
  1147. * @returns {string} result
  1148. */
  1149. const joinOneLine = (items) =>
  1150. items
  1151. .map((item) => item.content)
  1152. .filter(Boolean)
  1153. .join(" ");
  1154. /**
  1155. * Returns result.
  1156. * @param {Item[]} items items
  1157. * @returns {string} result
  1158. */
  1159. const joinInBrackets = (items) => {
  1160. /** @type {string[]} */
  1161. const res = [];
  1162. let mode = 0;
  1163. for (const item of items) {
  1164. if (item.element === "separator!") {
  1165. switch (mode) {
  1166. case 0:
  1167. case 1:
  1168. mode += 2;
  1169. break;
  1170. case 4:
  1171. res.push(")");
  1172. mode = 3;
  1173. break;
  1174. }
  1175. }
  1176. if (!item.content) continue;
  1177. switch (mode) {
  1178. case 0:
  1179. mode = 1;
  1180. break;
  1181. case 1:
  1182. res.push(" ");
  1183. break;
  1184. case 2:
  1185. res.push("(");
  1186. mode = 4;
  1187. break;
  1188. case 3:
  1189. res.push(" (");
  1190. mode = 4;
  1191. break;
  1192. case 4:
  1193. res.push(", ");
  1194. break;
  1195. }
  1196. res.push(item.content);
  1197. }
  1198. if (mode === 4) res.push(")");
  1199. return res.join("");
  1200. };
  1201. /**
  1202. * Returns result.
  1203. * @param {string} str a string
  1204. * @param {string} prefix prefix
  1205. * @param {boolean=} noPrefixInFirstLine need prefix in the first line?
  1206. * @returns {string} result
  1207. */
  1208. const indent = (str, prefix, noPrefixInFirstLine) => {
  1209. const rem = str.replace(/\n([^\n])/g, `\n${prefix}$1`);
  1210. if (noPrefixInFirstLine) return rem;
  1211. const ind = str[0] === "\n" ? "" : prefix;
  1212. return ind + rem;
  1213. };
  1214. /**
  1215. * Join explicit new line.
  1216. * @param {(false | Item)[]} items items
  1217. * @param {string} indenter indenter
  1218. * @returns {string} result
  1219. */
  1220. const joinExplicitNewLine = (items, indenter) => {
  1221. let firstInLine = true;
  1222. let first = true;
  1223. return items
  1224. .map((item) => {
  1225. if (!item || !item.content) return;
  1226. let content = indent(item.content, first ? "" : indenter, !firstInLine);
  1227. if (firstInLine) {
  1228. content = content.replace(/^\n+/, "");
  1229. }
  1230. if (!content) return;
  1231. first = false;
  1232. const noJoiner = firstInLine || content.startsWith("\n");
  1233. firstInLine = content.endsWith("\n");
  1234. return noJoiner ? content : ` ${content}`;
  1235. })
  1236. .filter(Boolean)
  1237. .join("")
  1238. .trim();
  1239. };
  1240. /**
  1241. * Returns joiner.
  1242. * @param {boolean} error is an error
  1243. * @returns {SimpleElementJoiner} joiner
  1244. */
  1245. const joinError =
  1246. (error) =>
  1247. /**
  1248. * Handles the callback logic for this hook.
  1249. * @param {Item[]} items items
  1250. * @param {StatsPrinterContextWithExtra} ctx context
  1251. * @returns {string} result
  1252. */
  1253. (items, { red, yellow }) =>
  1254. `${error ? red("ERROR") : yellow("WARNING")} in ${joinExplicitNewLine(
  1255. items,
  1256. ""
  1257. )}`;
  1258. /** @typedef {{ element: string, content: string | undefined }} Item */
  1259. /** @typedef {(items: Item[], context: StatsPrinterContextWithExtra & Required<KnownStatsPrinterContext>) => string} SimpleElementJoiner */
  1260. /** @type {Record<string, SimpleElementJoiner>} */
  1261. const SIMPLE_ELEMENT_JOINERS = {
  1262. compilation: (items) => {
  1263. /** @type {string[]} */
  1264. const result = [];
  1265. let lastNeedMore = false;
  1266. for (const item of items) {
  1267. if (!item.content) continue;
  1268. const needMoreSpace =
  1269. item.element === "warnings" ||
  1270. item.element === "filteredWarningDetailsCount" ||
  1271. item.element === "errors" ||
  1272. item.element === "filteredErrorDetailsCount" ||
  1273. item.element === "logging";
  1274. if (result.length !== 0) {
  1275. result.push(needMoreSpace || lastNeedMore ? "\n\n" : "\n");
  1276. }
  1277. result.push(item.content);
  1278. lastNeedMore = needMoreSpace;
  1279. }
  1280. if (lastNeedMore) result.push("\n");
  1281. return result.join("");
  1282. },
  1283. asset: (items) =>
  1284. joinExplicitNewLine(
  1285. items.map((item) => {
  1286. if (
  1287. (item.element === "related" || item.element === "children") &&
  1288. item.content
  1289. ) {
  1290. return {
  1291. ...item,
  1292. content: `\n${item.content}\n`
  1293. };
  1294. }
  1295. return item;
  1296. }),
  1297. " "
  1298. ),
  1299. "asset.info": joinOneLine,
  1300. module: (items, { module }) => {
  1301. let hasName = false;
  1302. return joinExplicitNewLine(
  1303. items.map((item) => {
  1304. switch (item.element) {
  1305. case "id":
  1306. if (module.id === module.name) {
  1307. if (hasName) return false;
  1308. if (item.content) hasName = true;
  1309. }
  1310. break;
  1311. case "name":
  1312. if (hasName) return false;
  1313. if (item.content) hasName = true;
  1314. break;
  1315. case "providedExports":
  1316. case "usedExports":
  1317. case "optimizationBailout":
  1318. case "reasons":
  1319. case "issuerPath":
  1320. case "profile":
  1321. case "children":
  1322. case "modules":
  1323. if (item.content) {
  1324. return {
  1325. ...item,
  1326. content: `\n${item.content}\n`
  1327. };
  1328. }
  1329. break;
  1330. }
  1331. return item;
  1332. }),
  1333. " "
  1334. );
  1335. },
  1336. chunk: (items) => {
  1337. let hasEntry = false;
  1338. return `chunk ${joinExplicitNewLine(
  1339. items.filter((item) => {
  1340. switch (item.element) {
  1341. case "entry":
  1342. if (item.content) hasEntry = true;
  1343. break;
  1344. case "initial":
  1345. if (hasEntry) return false;
  1346. break;
  1347. }
  1348. return true;
  1349. }),
  1350. " "
  1351. )}`;
  1352. },
  1353. "chunk.childrenByOrder[]": (items) => `(${joinOneLine(items)})`,
  1354. chunkGroup: (items) => joinExplicitNewLine(items, " "),
  1355. chunkGroupAsset: joinOneLine,
  1356. chunkGroupChildGroup: joinOneLine,
  1357. chunkGroupChild: joinOneLine,
  1358. moduleReason: (items, { moduleReason }) => {
  1359. let hasName = false;
  1360. return joinExplicitNewLine(
  1361. items.map((item) => {
  1362. switch (item.element) {
  1363. case "moduleId":
  1364. if (moduleReason.moduleId === moduleReason.module && item.content) {
  1365. hasName = true;
  1366. }
  1367. break;
  1368. case "module":
  1369. if (hasName) return false;
  1370. break;
  1371. case "resolvedModule":
  1372. if (moduleReason.module === moduleReason.resolvedModule) {
  1373. return false;
  1374. }
  1375. break;
  1376. case "children":
  1377. if (item.content) {
  1378. return {
  1379. ...item,
  1380. content: `\n${item.content}\n`
  1381. };
  1382. }
  1383. break;
  1384. }
  1385. return item;
  1386. }),
  1387. " "
  1388. );
  1389. },
  1390. "module.profile": joinInBrackets,
  1391. moduleIssuer: joinOneLine,
  1392. chunkOrigin: (items) => `> ${joinOneLine(items)}`,
  1393. "errors[].error": joinError(true),
  1394. "warnings[].error": joinError(false),
  1395. error: (items) => joinExplicitNewLine(items, ""),
  1396. "error.errors[].error": (items) =>
  1397. indent(`[errors]: ${joinExplicitNewLine(items, "")}`, " "),
  1398. loggingGroup: (items) => joinExplicitNewLine(items, "").trimEnd(),
  1399. moduleTraceItem: (items) => ` @ ${joinOneLine(items)}`,
  1400. moduleTraceDependency: joinOneLine
  1401. };
  1402. /** @type {Record<keyof KnownStatsPrinterColorFunctions, string>} */
  1403. const AVAILABLE_COLORS = {
  1404. bold: "\u001B[1m",
  1405. yellow: "\u001B[1m\u001B[33m",
  1406. red: "\u001B[1m\u001B[31m",
  1407. green: "\u001B[1m\u001B[32m",
  1408. cyan: "\u001B[1m\u001B[36m",
  1409. magenta: "\u001B[1m\u001B[35m"
  1410. };
  1411. /**
  1412. * Defines the tail type used by this module.
  1413. * @template T
  1414. * @typedef {T extends [infer Head, ...infer Tail] ? Tail : undefined} Tail
  1415. */
  1416. /**
  1417. * Defines the tail parameters type used by this module.
  1418. * @template {(...args: EXPECTED_ANY[]) => EXPECTED_ANY} T
  1419. * @typedef {T extends (firstArg: EXPECTED_ANY, ...rest: infer R) => EXPECTED_ANY ? R : never} TailParameters
  1420. */
  1421. /** @typedef {{ [Key in keyof KnownStatsPrinterFormatters]: (value: Parameters<NonNullable<KnownStatsPrinterFormatters[Key]>>[0], options: Required<KnownStatsPrinterColorFunctions> & StatsPrinterContextWithExtra, ...args: TailParameters<NonNullable<KnownStatsPrinterFormatters[Key]>>) => string }} AvailableFormats */
  1422. /** @type {AvailableFormats} */
  1423. const AVAILABLE_FORMATS = {
  1424. formatChunkId: (id, { yellow }, direction) => {
  1425. switch (direction) {
  1426. case "parent":
  1427. return `<{${yellow(id)}}>`;
  1428. case "sibling":
  1429. return `={${yellow(id)}}=`;
  1430. case "child":
  1431. return `>{${yellow(id)}}<`;
  1432. default:
  1433. return `{${yellow(id)}}`;
  1434. }
  1435. },
  1436. formatModuleId: (id) => `[${id}]`,
  1437. formatFilename: (filename, { green, yellow }, oversize) =>
  1438. (oversize ? yellow : green)(filename),
  1439. formatFlag: (flag) => `[${flag}]`,
  1440. formatLayer: (layer) => `(in ${layer})`,
  1441. formatSize: require("../SizeFormatHelpers").formatSize,
  1442. formatDateTime: (dateTime, { bold }) => {
  1443. const d = new Date(dateTime);
  1444. const x = twoDigit;
  1445. const date = `${d.getFullYear()}-${x(d.getMonth() + 1)}-${x(d.getDate())}`;
  1446. const time = `${x(d.getHours())}:${x(d.getMinutes())}:${x(d.getSeconds())}`;
  1447. return `${date} ${bold(time)}`;
  1448. },
  1449. formatTime: (
  1450. time,
  1451. { timeReference, bold, green, yellow, red },
  1452. boldQuantity
  1453. ) => {
  1454. const unit = " ms";
  1455. if (timeReference && time !== timeReference) {
  1456. const times = [
  1457. timeReference / 2,
  1458. timeReference / 4,
  1459. timeReference / 8,
  1460. timeReference / 16
  1461. ];
  1462. if (time < times[3]) return `${time}${unit}`;
  1463. else if (time < times[2]) return bold(`${time}${unit}`);
  1464. else if (time < times[1]) return green(`${time}${unit}`);
  1465. else if (time < times[0]) return yellow(`${time}${unit}`);
  1466. return red(`${time}${unit}`);
  1467. }
  1468. return `${boldQuantity ? bold(time) : time}${unit}`;
  1469. },
  1470. formatError: (message, { green, yellow, red }) => {
  1471. if (message.includes("\u001B[")) return message;
  1472. const highlights = [
  1473. { regExp: /(Did you mean .+)/g, format: green },
  1474. {
  1475. regExp: /(Set 'mode' option to 'development' or 'production')/g,
  1476. format: green
  1477. },
  1478. { regExp: /(\(module has no exports\))/g, format: red },
  1479. { regExp: /\(possible exports: (.+)\)/g, format: green },
  1480. { regExp: /(?:^|\n)(.* doesn't exist)/g, format: red },
  1481. { regExp: /('\w+' option has not been set)/g, format: red },
  1482. {
  1483. regExp: /(Emitted value instead of an instance of Error)/g,
  1484. format: yellow
  1485. },
  1486. { regExp: /(Used? .+ instead)/gi, format: yellow },
  1487. { regExp: /\b(deprecated|must|required)\b/g, format: yellow },
  1488. {
  1489. regExp: /\b(BREAKING CHANGE)\b/gi,
  1490. format: red
  1491. },
  1492. {
  1493. regExp:
  1494. /\b(error|failed|unexpected|invalid|not found|not supported|not available|not possible|not implemented|doesn't support|conflict|conflicting|not existing|duplicate)\b/gi,
  1495. format: red
  1496. }
  1497. ];
  1498. for (const { regExp, format } of highlights) {
  1499. message = message.replace(
  1500. regExp,
  1501. /**
  1502. * Handles the format callback for this hook.
  1503. * @param {string} match match
  1504. * @param {string} content content
  1505. * @returns {string} result
  1506. */
  1507. (match, content) => match.replace(content, format(content))
  1508. );
  1509. }
  1510. return message;
  1511. }
  1512. };
  1513. /** @typedef {(result: string) => string} ResultModifierFn */
  1514. /** @type {Record<string, ResultModifierFn>} */
  1515. const RESULT_MODIFIER = {
  1516. "module.modules": (result) => indent(result, "| ")
  1517. };
  1518. /**
  1519. * Creates an order from the provided array.
  1520. * @param {string[]} array array
  1521. * @param {string[]} preferredOrder preferred order
  1522. * @returns {string[]} result
  1523. */
  1524. const createOrder = (array, preferredOrder) => {
  1525. const originalArray = [...array];
  1526. /** @type {Set<string>} */
  1527. const set = new Set(array);
  1528. /** @type {Set<string>} */
  1529. const usedSet = new Set();
  1530. array.length = 0;
  1531. for (const element of preferredOrder) {
  1532. if (element.endsWith("!") || set.has(element)) {
  1533. array.push(element);
  1534. usedSet.add(element);
  1535. }
  1536. }
  1537. for (const element of originalArray) {
  1538. if (!usedSet.has(element)) {
  1539. array.push(element);
  1540. }
  1541. }
  1542. return array;
  1543. };
  1544. const PLUGIN_NAME = "DefaultStatsPrinterPlugin";
  1545. class DefaultStatsPrinterPlugin {
  1546. /**
  1547. * Applies the plugin by registering its hooks on the compiler.
  1548. * @param {Compiler} compiler the compiler instance
  1549. * @returns {void}
  1550. */
  1551. apply(compiler) {
  1552. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
  1553. compilation.hooks.statsPrinter.tap(PLUGIN_NAME, (stats, options) => {
  1554. // Put colors into context
  1555. stats.hooks.print
  1556. .for("compilation")
  1557. .tap(PLUGIN_NAME, (compilation, context) => {
  1558. for (const color of Object.keys(AVAILABLE_COLORS)) {
  1559. const name =
  1560. /** @type {keyof KnownStatsPrinterColorFunctions} */
  1561. (color);
  1562. /** @type {string | undefined} */
  1563. let start;
  1564. if (options.colors) {
  1565. if (
  1566. typeof options.colors === "object" &&
  1567. typeof options.colors[name] === "string"
  1568. ) {
  1569. start = options.colors[name];
  1570. } else {
  1571. start = AVAILABLE_COLORS[name];
  1572. }
  1573. }
  1574. if (start) {
  1575. /** @type {ColorFunction} */
  1576. context[color] = (str) =>
  1577. `${start}${
  1578. typeof str === "string"
  1579. ? str.replace(
  1580. // eslint-disable-next-line no-control-regex
  1581. /((\u001B\[39m|\u001B\[22m|\u001B\[0m)+)/g,
  1582. `$1${start}`
  1583. )
  1584. : str
  1585. }\u001B[39m\u001B[22m`;
  1586. } else {
  1587. /**
  1588. * Returns str string.
  1589. * @param {string} str string
  1590. * @returns {string} str string
  1591. */
  1592. context[color] = (str) => str;
  1593. }
  1594. }
  1595. for (const format of /** @type {(keyof KnownStatsPrinterFormatters)[]} */ (
  1596. Object.keys(AVAILABLE_FORMATS)
  1597. )) {
  1598. context[format] =
  1599. /** @type {(content: Parameters<NonNullable<KnownStatsPrinterFormatters[keyof KnownStatsPrinterFormatters]>>[0], ...args: Tail<Parameters<NonNullable<KnownStatsPrinterFormatters[keyof KnownStatsPrinterFormatters]>>>) => string} */
  1600. (content, ...args) =>
  1601. /** @type {EXPECTED_ANY} */
  1602. (AVAILABLE_FORMATS[format])(
  1603. content,
  1604. /** @type {StatsPrinterContext & Required<KnownStatsPrinterColorFunctions>} */
  1605. (context),
  1606. ...args
  1607. );
  1608. }
  1609. context.timeReference = compilation.time;
  1610. });
  1611. for (const key of /** @type {(keyof CompilationSimplePrinters)[]} */ (
  1612. Object.keys(COMPILATION_SIMPLE_PRINTERS)
  1613. )) {
  1614. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1615. /** @type {EXPECTED_ANY} */
  1616. (COMPILATION_SIMPLE_PRINTERS)[key](
  1617. obj,
  1618. /** @type {DefineStatsPrinterContext<"compilation">} */
  1619. (ctx),
  1620. stats
  1621. )
  1622. );
  1623. }
  1624. for (const key of /** @type {(keyof AssetSimplePrinters)[]} */ (
  1625. Object.keys(ASSET_SIMPLE_PRINTERS)
  1626. )) {
  1627. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1628. /** @type {NonNullable<AssetSimplePrinters[keyof AssetSimplePrinters]>} */
  1629. (ASSET_SIMPLE_PRINTERS[key])(
  1630. obj,
  1631. /** @type {DefineStatsPrinterContext<"asset" | "asset.info">} */
  1632. (ctx),
  1633. stats
  1634. )
  1635. );
  1636. }
  1637. for (const key of /** @type {(keyof ModuleSimplePrinters)[]} */ (
  1638. Object.keys(MODULE_SIMPLE_PRINTERS)
  1639. )) {
  1640. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1641. /** @type {EXPECTED_ANY} */
  1642. (MODULE_SIMPLE_PRINTERS)[key](
  1643. obj,
  1644. /** @type {DefineStatsPrinterContext<"module">} */
  1645. (ctx),
  1646. stats
  1647. )
  1648. );
  1649. }
  1650. for (const key of /** @type {(keyof ModuleIssuerPrinters)[]} */ (
  1651. Object.keys(MODULE_ISSUER_PRINTERS)
  1652. )) {
  1653. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1654. /** @type {NonNullable<ModuleIssuerPrinters[keyof ModuleIssuerPrinters]>} */
  1655. (MODULE_ISSUER_PRINTERS[key])(
  1656. obj,
  1657. /** @type {DefineStatsPrinterContext<"moduleIssuer">} */
  1658. (ctx),
  1659. stats
  1660. )
  1661. );
  1662. }
  1663. for (const key of /** @type {(keyof ModuleReasonsPrinters)[]} */ (
  1664. Object.keys(MODULE_REASON_PRINTERS)
  1665. )) {
  1666. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1667. /** @type {EXPECTED_ANY} */
  1668. (MODULE_REASON_PRINTERS)[key](
  1669. obj,
  1670. /** @type {DefineStatsPrinterContext<"moduleReason">} */
  1671. (ctx),
  1672. stats
  1673. )
  1674. );
  1675. }
  1676. for (const key of /** @type {(keyof ModuleProfilePrinters)[]} */ (
  1677. Object.keys(MODULE_PROFILE_PRINTERS)
  1678. )) {
  1679. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1680. /** @type {NonNullable<ModuleProfilePrinters[keyof ModuleProfilePrinters]>} */
  1681. (MODULE_PROFILE_PRINTERS[key])(
  1682. obj,
  1683. /** @type {DefineStatsPrinterContext<"profile">} */
  1684. (ctx),
  1685. stats
  1686. )
  1687. );
  1688. }
  1689. for (const key of /** @type {(keyof ChunkGroupPrinters)[]} */ (
  1690. Object.keys(CHUNK_GROUP_PRINTERS)
  1691. )) {
  1692. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1693. /** @type {EXPECTED_ANY} */
  1694. (CHUNK_GROUP_PRINTERS)[key](
  1695. obj,
  1696. /** @type {DefineStatsPrinterContext<"chunkGroupKind" | "chunkGroup">} */
  1697. (ctx),
  1698. stats
  1699. )
  1700. );
  1701. }
  1702. for (const key of /** @type {(keyof ChunkPrinters)[]} */ (
  1703. Object.keys(CHUNK_PRINTERS)
  1704. )) {
  1705. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1706. /** @type {EXPECTED_ANY} */
  1707. (CHUNK_PRINTERS)[key](
  1708. obj,
  1709. /** @type {DefineStatsPrinterContext<"chunk">} */
  1710. (ctx),
  1711. stats
  1712. )
  1713. );
  1714. }
  1715. for (const key of /** @type {(keyof ErrorPrinters)[]} */ (
  1716. Object.keys(ERROR_PRINTERS)
  1717. )) {
  1718. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1719. /** @type {EXPECTED_ANY} */
  1720. (ERROR_PRINTERS)[key](
  1721. obj,
  1722. /** @type {DefineStatsPrinterContext<"error">} */
  1723. (ctx),
  1724. stats
  1725. )
  1726. );
  1727. }
  1728. for (const key of /** @type {(keyof LogEntryPrinters)[]} */ (
  1729. Object.keys(LOG_ENTRY_PRINTERS)
  1730. )) {
  1731. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1732. /** @type {EXPECTED_ANY} */
  1733. (LOG_ENTRY_PRINTERS)[key](
  1734. obj,
  1735. /** @type {DefineStatsPrinterContext<"logging">} */
  1736. (ctx),
  1737. stats
  1738. )
  1739. );
  1740. }
  1741. for (const key of /** @type {(keyof ModuleTraceDependencyPrinters)[]} */ (
  1742. Object.keys(MODULE_TRACE_DEPENDENCY_PRINTERS)
  1743. )) {
  1744. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1745. /** @type {NonNullable<ModuleTraceDependencyPrinters[keyof ModuleTraceDependencyPrinters]>} */
  1746. (MODULE_TRACE_DEPENDENCY_PRINTERS[key])(
  1747. obj,
  1748. /** @type {DefineStatsPrinterContext<"moduleTraceDependency">} */
  1749. (ctx),
  1750. stats
  1751. )
  1752. );
  1753. }
  1754. for (const key of /** @type {(keyof ModuleTraceItemPrinters)[]} */ (
  1755. Object.keys(MODULE_TRACE_ITEM_PRINTERS)
  1756. )) {
  1757. stats.hooks.print.for(key).tap(PLUGIN_NAME, (obj, ctx) =>
  1758. /** @type {NonNullable<ModuleTraceItemPrinters[keyof ModuleTraceItemPrinters]>} */
  1759. (MODULE_TRACE_ITEM_PRINTERS[key])(
  1760. obj,
  1761. /** @type {DefineStatsPrinterContext<"moduleTraceItem">} */
  1762. (ctx),
  1763. stats
  1764. )
  1765. );
  1766. }
  1767. for (const key of Object.keys(PREFERRED_ORDERS)) {
  1768. const preferredOrder = PREFERRED_ORDERS[key];
  1769. stats.hooks.sortElements
  1770. .for(key)
  1771. .tap(PLUGIN_NAME, (elements, _context) => {
  1772. createOrder(elements, preferredOrder);
  1773. });
  1774. }
  1775. for (const key of Object.keys(ITEM_NAMES)) {
  1776. const itemName = ITEM_NAMES[key];
  1777. stats.hooks.getItemName
  1778. .for(key)
  1779. .tap(
  1780. PLUGIN_NAME,
  1781. typeof itemName === "string" ? () => itemName : itemName
  1782. );
  1783. }
  1784. for (const key of Object.keys(SIMPLE_ITEMS_JOINER)) {
  1785. const joiner = SIMPLE_ITEMS_JOINER[key];
  1786. stats.hooks.printItems.for(key).tap(PLUGIN_NAME, joiner);
  1787. }
  1788. for (const key of Object.keys(SIMPLE_ELEMENT_JOINERS)) {
  1789. const joiner =
  1790. /** @type {(items: Item[], context: StatsPrinterContext) => string} */
  1791. (SIMPLE_ELEMENT_JOINERS[key]);
  1792. stats.hooks.printElements.for(key).tap(PLUGIN_NAME, joiner);
  1793. }
  1794. for (const key of Object.keys(RESULT_MODIFIER)) {
  1795. const modifier = RESULT_MODIFIER[key];
  1796. stats.hooks.result.for(key).tap(PLUGIN_NAME, modifier);
  1797. }
  1798. });
  1799. });
  1800. }
  1801. }
  1802. module.exports = DefaultStatsPrinterPlugin;