DefaultStatsPrinterPlugin.js 57 KB

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