source: frontend/node_modules/webpack/lib/stats/DefaultStatsPrinterPlugin.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

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