UNPKG

41.1 kBJavaScriptView Raw
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("./StatsPrinter")} StatsPrinter */
10/** @typedef {import("./StatsPrinter").StatsPrinterContext} StatsPrinterContext */
11
12const DATA_URI_CONTENT_LENGTH = 16;
13
14const plural = (n, singular, plural) => (n === 1 ? singular : plural);
15
16/**
17 * @param {Record<string, number>} sizes sizes by source type
18 * @param {Object} options options
19 * @param {(number) => string=} options.formatSize size formatter
20 * @returns {string} text
21 */
22const printSizes = (sizes, { formatSize = n => `${n}` }) => {
23 const keys = Object.keys(sizes);
24 if (keys.length > 1) {
25 return keys.map(key => `${formatSize(sizes[key])} (${key})`).join(" ");
26 } else if (keys.length === 1) {
27 return formatSize(sizes[keys[0]]);
28 }
29};
30
31const getResourceName = resource => {
32 const dataUrl = /^data:[^,]+,/.exec(resource);
33 if (!dataUrl) return resource;
34
35 const len = dataUrl[0].length + DATA_URI_CONTENT_LENGTH;
36 if (resource.length < len) return resource;
37 return `${resource.slice(
38 0,
39 Math.min(resource.length - /* '..'.length */ 2, len)
40 )}..`;
41};
42
43const getModuleName = name => {
44 const [, prefix, resource] = /^(.*!)?([^!]*)$/.exec(name);
45 return [prefix, getResourceName(resource)];
46};
47
48const mapLines = (str, fn) => str.split("\n").map(fn).join("\n");
49
50/**
51 * @param {number} n a number
52 * @returns {string} number as two digit string, leading 0
53 */
54const twoDigit = n => (n >= 10 ? `${n}` : `0${n}`);
55
56const isValidId = id => {
57 return typeof id === "number" || id;
58};
59
60const moreCount = (list, count) => {
61 return list && list.length > 0 ? `+ ${count}` : `${count}`;
62};
63
64/** @type {Record<string, (thing: any, context: StatsPrinterContext, printer: StatsPrinter) => string | void>} */
65const SIMPLE_PRINTERS = {
66 "compilation.summary!": (
67 _,
68 {
69 type,
70 bold,
71 green,
72 red,
73 yellow,
74 formatDateTime,
75 formatTime,
76 compilation: {
77 name,
78 hash,
79 version,
80 time,
81 builtAt,
82 errorsCount,
83 warningsCount
84 }
85 }
86 ) => {
87 const root = type === "compilation.summary!";
88 const warningsMessage =
89 warningsCount > 0
90 ? yellow(
91 `${warningsCount} ${plural(warningsCount, "warning", "warnings")}`
92 )
93 : "";
94 const errorsMessage =
95 errorsCount > 0
96 ? red(`${errorsCount} ${plural(errorsCount, "error", "errors")}`)
97 : "";
98 const timeMessage = root && time ? ` in ${formatTime(time)}` : "";
99 const hashMessage = hash ? ` (${hash})` : "";
100 const builtAtMessage =
101 root && builtAt ? `${formatDateTime(builtAt)}: ` : "";
102 const versionMessage = root && version ? `webpack ${version}` : "";
103 const nameMessage =
104 root && name
105 ? bold(name)
106 : name
107 ? `Child ${bold(name)}`
108 : root
109 ? ""
110 : "Child";
111 const subjectMessage =
112 nameMessage && versionMessage
113 ? `${nameMessage} (${versionMessage})`
114 : versionMessage || nameMessage || "webpack";
115 let statusMessage;
116 if (errorsMessage && warningsMessage) {
117 statusMessage = `compiled with ${errorsMessage} and ${warningsMessage}`;
118 } else if (errorsMessage) {
119 statusMessage = `compiled with ${errorsMessage}`;
120 } else if (warningsMessage) {
121 statusMessage = `compiled with ${warningsMessage}`;
122 } else if (errorsCount === 0 && warningsCount === 0) {
123 statusMessage = `compiled ${green("successfully")}`;
124 } else {
125 statusMessage = `compiled`;
126 }
127 if (
128 builtAtMessage ||
129 versionMessage ||
130 errorsMessage ||
131 warningsMessage ||
132 (errorsCount === 0 && warningsCount === 0) ||
133 timeMessage ||
134 hashMessage
135 )
136 return `${builtAtMessage}${subjectMessage} ${statusMessage}${timeMessage}${hashMessage}`;
137 },
138 "compilation.filteredWarningDetailsCount": count =>
139 count
140 ? `${count} ${plural(
141 count,
142 "warning has",
143 "warnings have"
144 )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
145 : undefined,
146 "compilation.filteredErrorDetailsCount": (count, { yellow }) =>
147 count
148 ? yellow(
149 `${count} ${plural(
150 count,
151 "error has",
152 "errors have"
153 )} detailed information that is not shown.\nUse 'stats.errorDetails: true' resp. '--stats-error-details' to show it.`
154 )
155 : undefined,
156 "compilation.env": (env, { bold }) =>
157 env
158 ? `Environment (--env): ${bold(JSON.stringify(env, null, 2))}`
159 : undefined,
160 "compilation.publicPath": (publicPath, { bold }) =>
161 `PublicPath: ${bold(publicPath || "(none)")}`,
162 "compilation.entrypoints": (entrypoints, context, printer) =>
163 Array.isArray(entrypoints)
164 ? undefined
165 : printer.print(context.type, Object.values(entrypoints), {
166 ...context,
167 chunkGroupKind: "Entrypoint"
168 }),
169 "compilation.namedChunkGroups": (namedChunkGroups, context, printer) => {
170 if (!Array.isArray(namedChunkGroups)) {
171 const {
172 compilation: { entrypoints }
173 } = context;
174 let chunkGroups = Object.values(namedChunkGroups);
175 if (entrypoints) {
176 chunkGroups = chunkGroups.filter(
177 group =>
178 !Object.prototype.hasOwnProperty.call(entrypoints, group.name)
179 );
180 }
181 return printer.print(context.type, chunkGroups, {
182 ...context,
183 chunkGroupKind: "Chunk Group"
184 });
185 }
186 },
187 "compilation.assetsByChunkName": () => "",
188
189 "compilation.filteredModules": (
190 filteredModules,
191 { compilation: { modules } }
192 ) =>
193 filteredModules > 0
194 ? `${moreCount(modules, filteredModules)} ${plural(
195 filteredModules,
196 "module",
197 "modules"
198 )}`
199 : undefined,
200 "compilation.filteredAssets": (filteredAssets, { compilation: { assets } }) =>
201 filteredAssets > 0
202 ? `${moreCount(assets, filteredAssets)} ${plural(
203 filteredAssets,
204 "asset",
205 "assets"
206 )}`
207 : undefined,
208 "compilation.logging": (logging, context, printer) =>
209 Array.isArray(logging)
210 ? undefined
211 : printer.print(
212 context.type,
213 Object.entries(logging).map(([name, value]) => ({ ...value, name })),
214 context
215 ),
216 "compilation.warningsInChildren!": (_, { yellow, compilation }) => {
217 if (
218 !compilation.children &&
219 compilation.warningsCount > 0 &&
220 compilation.warnings
221 ) {
222 const childWarnings =
223 compilation.warningsCount - compilation.warnings.length;
224 if (childWarnings > 0) {
225 return yellow(
226 `${childWarnings} ${plural(
227 childWarnings,
228 "WARNING",
229 "WARNINGS"
230 )} in child compilations${
231 compilation.children
232 ? ""
233 : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
234 }`
235 );
236 }
237 }
238 },
239 "compilation.errorsInChildren!": (_, { red, compilation }) => {
240 if (
241 !compilation.children &&
242 compilation.errorsCount > 0 &&
243 compilation.errors
244 ) {
245 const childErrors = compilation.errorsCount - compilation.errors.length;
246 if (childErrors > 0) {
247 return red(
248 `${childErrors} ${plural(
249 childErrors,
250 "ERROR",
251 "ERRORS"
252 )} in child compilations${
253 compilation.children
254 ? ""
255 : " (Use 'stats.children: true' resp. '--stats-children' for more details)"
256 }`
257 );
258 }
259 }
260 },
261
262 "asset.type": type => type,
263 "asset.name": (name, { formatFilename, asset: { isOverSizeLimit } }) =>
264 formatFilename(name, isOverSizeLimit),
265 "asset.size": (
266 size,
267 { asset: { isOverSizeLimit }, yellow, green, formatSize }
268 ) => (isOverSizeLimit ? yellow(formatSize(size)) : formatSize(size)),
269 "asset.emitted": (emitted, { green, formatFlag }) =>
270 emitted ? green(formatFlag("emitted")) : undefined,
271 "asset.comparedForEmit": (comparedForEmit, { yellow, formatFlag }) =>
272 comparedForEmit ? yellow(formatFlag("compared for emit")) : undefined,
273 "asset.cached": (cached, { green, formatFlag }) =>
274 cached ? green(formatFlag("cached")) : undefined,
275 "asset.isOverSizeLimit": (isOverSizeLimit, { yellow, formatFlag }) =>
276 isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
277
278 "asset.info.immutable": (immutable, { green, formatFlag }) =>
279 immutable ? green(formatFlag("immutable")) : undefined,
280 "asset.info.javascriptModule": (javascriptModule, { formatFlag }) =>
281 javascriptModule ? formatFlag("javascript module") : undefined,
282 "asset.info.sourceFilename": (sourceFilename, { formatFlag }) =>
283 sourceFilename
284 ? formatFlag(
285 sourceFilename === true
286 ? "from source file"
287 : `from: ${sourceFilename}`
288 )
289 : undefined,
290 "asset.info.development": (development, { green, formatFlag }) =>
291 development ? green(formatFlag("dev")) : undefined,
292 "asset.info.hotModuleReplacement": (
293 hotModuleReplacement,
294 { green, formatFlag }
295 ) => (hotModuleReplacement ? green(formatFlag("hmr")) : undefined),
296 "asset.separator!": () => "\n",
297 "asset.filteredRelated": (filteredRelated, { asset: { related } }) =>
298 filteredRelated > 0
299 ? `${moreCount(related, filteredRelated)} related ${plural(
300 filteredRelated,
301 "asset",
302 "assets"
303 )}`
304 : undefined,
305 "asset.filteredChildren": (filteredChildren, { asset: { children } }) =>
306 filteredChildren > 0
307 ? `${moreCount(children, filteredChildren)} ${plural(
308 filteredChildren,
309 "asset",
310 "assets"
311 )}`
312 : undefined,
313
314 assetChunk: (id, { formatChunkId }) => formatChunkId(id),
315
316 assetChunkName: name => name,
317 assetChunkIdHint: name => name,
318
319 "module.type": type => (type !== "module" ? type : undefined),
320 "module.id": (id, { formatModuleId }) =>
321 isValidId(id) ? formatModuleId(id) : undefined,
322 "module.name": (name, { bold }) => {
323 const [prefix, resource] = getModuleName(name);
324 return `${prefix || ""}${bold(resource || "")}`;
325 },
326 "module.identifier": identifier => undefined,
327 "module.layer": (layer, { formatLayer }) =>
328 layer ? formatLayer(layer) : undefined,
329 "module.sizes": printSizes,
330 "module.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
331 "module.depth": (depth, { formatFlag }) =>
332 depth !== null ? formatFlag(`depth ${depth}`) : undefined,
333 "module.cacheable": (cacheable, { formatFlag, red }) =>
334 cacheable === false ? red(formatFlag("not cacheable")) : undefined,
335 "module.orphan": (orphan, { formatFlag, yellow }) =>
336 orphan ? yellow(formatFlag("orphan")) : undefined,
337 "module.runtime": (runtime, { formatFlag, yellow }) =>
338 runtime ? yellow(formatFlag("runtime")) : undefined,
339 "module.optional": (optional, { formatFlag, yellow }) =>
340 optional ? yellow(formatFlag("optional")) : undefined,
341 "module.dependent": (dependent, { formatFlag, cyan }) =>
342 dependent ? cyan(formatFlag("dependent")) : undefined,
343 "module.built": (built, { formatFlag, yellow }) =>
344 built ? yellow(formatFlag("built")) : undefined,
345 "module.codeGenerated": (codeGenerated, { formatFlag, yellow }) =>
346 codeGenerated ? yellow(formatFlag("code generated")) : undefined,
347 "module.buildTimeExecuted": (buildTimeExecuted, { formatFlag, green }) =>
348 buildTimeExecuted ? green(formatFlag("build time executed")) : undefined,
349 "module.cached": (cached, { formatFlag, green }) =>
350 cached ? green(formatFlag("cached")) : undefined,
351 "module.assets": (assets, { formatFlag, magenta }) =>
352 assets && assets.length
353 ? magenta(
354 formatFlag(
355 `${assets.length} ${plural(assets.length, "asset", "assets")}`
356 )
357 )
358 : undefined,
359 "module.warnings": (warnings, { formatFlag, yellow }) =>
360 warnings === true
361 ? yellow(formatFlag("warnings"))
362 : warnings
363 ? yellow(
364 formatFlag(`${warnings} ${plural(warnings, "warning", "warnings")}`)
365 )
366 : undefined,
367 "module.errors": (errors, { formatFlag, red }) =>
368 errors === true
369 ? red(formatFlag("errors"))
370 : errors
371 ? red(formatFlag(`${errors} ${plural(errors, "error", "errors")}`))
372 : undefined,
373 "module.providedExports": (providedExports, { formatFlag, cyan }) => {
374 if (Array.isArray(providedExports)) {
375 if (providedExports.length === 0) return cyan(formatFlag("no exports"));
376 return cyan(formatFlag(`exports: ${providedExports.join(", ")}`));
377 }
378 },
379 "module.usedExports": (usedExports, { formatFlag, cyan, module }) => {
380 if (usedExports !== true) {
381 if (usedExports === null) return cyan(formatFlag("used exports unknown"));
382 if (usedExports === false) return cyan(formatFlag("module unused"));
383 if (Array.isArray(usedExports)) {
384 if (usedExports.length === 0)
385 return cyan(formatFlag("no exports used"));
386 const providedExportsCount = Array.isArray(module.providedExports)
387 ? module.providedExports.length
388 : null;
389 if (
390 providedExportsCount !== null &&
391 providedExportsCount === usedExports.length
392 ) {
393 return cyan(formatFlag("all exports used"));
394 } else {
395 return cyan(
396 formatFlag(`only some exports used: ${usedExports.join(", ")}`)
397 );
398 }
399 }
400 }
401 },
402 "module.optimizationBailout[]": (optimizationBailout, { yellow }) =>
403 yellow(optimizationBailout),
404 "module.issuerPath": (issuerPath, { module }) =>
405 module.profile ? undefined : "",
406 "module.profile": profile => undefined,
407 "module.filteredModules": (filteredModules, { module: { modules } }) =>
408 filteredModules > 0
409 ? `${moreCount(modules, filteredModules)} nested ${plural(
410 filteredModules,
411 "module",
412 "modules"
413 )}`
414 : undefined,
415 "module.filteredReasons": (filteredReasons, { module: { reasons } }) =>
416 filteredReasons > 0
417 ? `${moreCount(reasons, filteredReasons)} ${plural(
418 filteredReasons,
419 "reason",
420 "reasons"
421 )}`
422 : undefined,
423 "module.filteredChildren": (filteredChildren, { module: { children } }) =>
424 filteredChildren > 0
425 ? `${moreCount(children, filteredChildren)} ${plural(
426 filteredChildren,
427 "module",
428 "modules"
429 )}`
430 : undefined,
431 "module.separator!": () => "\n",
432
433 "moduleIssuer.id": (id, { formatModuleId }) => formatModuleId(id),
434 "moduleIssuer.profile.total": (value, { formatTime }) => formatTime(value),
435
436 "moduleReason.type": type => type,
437 "moduleReason.userRequest": (userRequest, { cyan }) =>
438 cyan(getResourceName(userRequest)),
439 "moduleReason.moduleId": (moduleId, { formatModuleId }) =>
440 isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
441 "moduleReason.module": (module, { magenta }) => magenta(module),
442 "moduleReason.loc": loc => loc,
443 "moduleReason.explanation": (explanation, { cyan }) => cyan(explanation),
444 "moduleReason.active": (active, { formatFlag }) =>
445 active ? undefined : formatFlag("inactive"),
446 "moduleReason.resolvedModule": (module, { magenta }) => magenta(module),
447 "moduleReason.filteredChildren": (
448 filteredChildren,
449 { moduleReason: { children } }
450 ) =>
451 filteredChildren > 0
452 ? `${moreCount(children, filteredChildren)} ${plural(
453 filteredChildren,
454 "reason",
455 "reasons"
456 )}`
457 : undefined,
458
459 "module.profile.total": (value, { formatTime }) => formatTime(value),
460 "module.profile.resolving": (value, { formatTime }) =>
461 `resolving: ${formatTime(value)}`,
462 "module.profile.restoring": (value, { formatTime }) =>
463 `restoring: ${formatTime(value)}`,
464 "module.profile.integration": (value, { formatTime }) =>
465 `integration: ${formatTime(value)}`,
466 "module.profile.building": (value, { formatTime }) =>
467 `building: ${formatTime(value)}`,
468 "module.profile.storing": (value, { formatTime }) =>
469 `storing: ${formatTime(value)}`,
470 "module.profile.additionalResolving": (value, { formatTime }) =>
471 value ? `additional resolving: ${formatTime(value)}` : undefined,
472 "module.profile.additionalIntegration": (value, { formatTime }) =>
473 value ? `additional integration: ${formatTime(value)}` : undefined,
474
475 "chunkGroup.kind!": (_, { chunkGroupKind }) => chunkGroupKind,
476 "chunkGroup.separator!": () => "\n",
477 "chunkGroup.name": (name, { bold }) => bold(name),
478 "chunkGroup.isOverSizeLimit": (isOverSizeLimit, { formatFlag, yellow }) =>
479 isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
480 "chunkGroup.assetsSize": (size, { formatSize }) =>
481 size ? formatSize(size) : undefined,
482 "chunkGroup.auxiliaryAssetsSize": (size, { formatSize }) =>
483 size ? `(${formatSize(size)})` : undefined,
484 "chunkGroup.filteredAssets": (n, { chunkGroup: { assets } }) =>
485 n > 0
486 ? `${moreCount(assets, n)} ${plural(n, "asset", "assets")}`
487 : undefined,
488 "chunkGroup.filteredAuxiliaryAssets": (
489 n,
490 { chunkGroup: { auxiliaryAssets } }
491 ) =>
492 n > 0
493 ? `${moreCount(auxiliaryAssets, n)} auxiliary ${plural(
494 n,
495 "asset",
496 "assets"
497 )}`
498 : undefined,
499 "chunkGroup.is!": () => "=",
500 "chunkGroupAsset.name": (asset, { green }) => green(asset),
501 "chunkGroupAsset.size": (size, { formatSize, chunkGroup }) =>
502 chunkGroup.assets.length > 1 ||
503 (chunkGroup.auxiliaryAssets && chunkGroup.auxiliaryAssets.length > 0)
504 ? formatSize(size)
505 : undefined,
506 "chunkGroup.children": (children, context, printer) =>
507 Array.isArray(children)
508 ? undefined
509 : printer.print(
510 context.type,
511 Object.keys(children).map(key => ({
512 type: key,
513 children: children[key]
514 })),
515 context
516 ),
517 "chunkGroupChildGroup.type": type => `${type}:`,
518 "chunkGroupChild.assets[]": (file, { formatFilename }) =>
519 formatFilename(file),
520 "chunkGroupChild.chunks[]": (id, { formatChunkId }) => formatChunkId(id),
521 "chunkGroupChild.name": name => (name ? `(name: ${name})` : undefined),
522
523 "chunk.id": (id, { formatChunkId }) => formatChunkId(id),
524 "chunk.files[]": (file, { formatFilename }) => formatFilename(file),
525 "chunk.names[]": name => name,
526 "chunk.idHints[]": name => name,
527 "chunk.runtime[]": name => name,
528 "chunk.sizes": (sizes, context) => printSizes(sizes, context),
529 "chunk.parents[]": (parents, context) =>
530 context.formatChunkId(parents, "parent"),
531 "chunk.siblings[]": (siblings, context) =>
532 context.formatChunkId(siblings, "sibling"),
533 "chunk.children[]": (children, context) =>
534 context.formatChunkId(children, "child"),
535 "chunk.childrenByOrder": (childrenByOrder, context, printer) =>
536 Array.isArray(childrenByOrder)
537 ? undefined
538 : printer.print(
539 context.type,
540 Object.keys(childrenByOrder).map(key => ({
541 type: key,
542 children: childrenByOrder[key]
543 })),
544 context
545 ),
546 "chunk.childrenByOrder[].type": type => `${type}:`,
547 "chunk.childrenByOrder[].children[]": (id, { formatChunkId }) =>
548 isValidId(id) ? formatChunkId(id) : undefined,
549 "chunk.entry": (entry, { formatFlag, yellow }) =>
550 entry ? yellow(formatFlag("entry")) : undefined,
551 "chunk.initial": (initial, { formatFlag, yellow }) =>
552 initial ? yellow(formatFlag("initial")) : undefined,
553 "chunk.rendered": (rendered, { formatFlag, green }) =>
554 rendered ? green(formatFlag("rendered")) : undefined,
555 "chunk.recorded": (recorded, { formatFlag, green }) =>
556 recorded ? green(formatFlag("recorded")) : undefined,
557 "chunk.reason": (reason, { yellow }) => (reason ? yellow(reason) : undefined),
558 "chunk.filteredModules": (filteredModules, { chunk: { modules } }) =>
559 filteredModules > 0
560 ? `${moreCount(modules, filteredModules)} chunk ${plural(
561 filteredModules,
562 "module",
563 "modules"
564 )}`
565 : undefined,
566 "chunk.separator!": () => "\n",
567
568 "chunkOrigin.request": request => request,
569 "chunkOrigin.moduleId": (moduleId, { formatModuleId }) =>
570 isValidId(moduleId) ? formatModuleId(moduleId) : undefined,
571 "chunkOrigin.moduleName": (moduleName, { bold }) => bold(moduleName),
572 "chunkOrigin.loc": loc => loc,
573
574 "error.compilerPath": (compilerPath, { bold }) =>
575 compilerPath ? bold(`(${compilerPath})`) : undefined,
576 "error.chunkId": (chunkId, { formatChunkId }) =>
577 isValidId(chunkId) ? formatChunkId(chunkId) : undefined,
578 "error.chunkEntry": (chunkEntry, { formatFlag }) =>
579 chunkEntry ? formatFlag("entry") : undefined,
580 "error.chunkInitial": (chunkInitial, { formatFlag }) =>
581 chunkInitial ? formatFlag("initial") : undefined,
582 "error.file": (file, { bold }) => bold(file),
583 "error.moduleName": (moduleName, { bold }) => {
584 return moduleName.includes("!")
585 ? `${bold(moduleName.replace(/^(\s|\S)*!/, ""))} (${moduleName})`
586 : `${bold(moduleName)}`;
587 },
588 "error.loc": (loc, { green }) => green(loc),
589 "error.message": (message, { bold, formatError }) =>
590 message.includes("\u001b[") ? message : bold(formatError(message)),
591 "error.details": (details, { formatError }) => formatError(details),
592 "error.stack": stack => stack,
593 "error.moduleTrace": moduleTrace => undefined,
594 "error.separator!": () => "\n",
595
596 "loggingEntry(error).loggingEntry.message": (message, { red }) =>
597 mapLines(message, x => `<e> ${red(x)}`),
598 "loggingEntry(warn).loggingEntry.message": (message, { yellow }) =>
599 mapLines(message, x => `<w> ${yellow(x)}`),
600 "loggingEntry(info).loggingEntry.message": (message, { green }) =>
601 mapLines(message, x => `<i> ${green(x)}`),
602 "loggingEntry(log).loggingEntry.message": (message, { bold }) =>
603 mapLines(message, x => ` ${bold(x)}`),
604 "loggingEntry(debug).loggingEntry.message": message =>
605 mapLines(message, x => ` ${x}`),
606 "loggingEntry(trace).loggingEntry.message": message =>
607 mapLines(message, x => ` ${x}`),
608 "loggingEntry(status).loggingEntry.message": (message, { magenta }) =>
609 mapLines(message, x => `<s> ${magenta(x)}`),
610 "loggingEntry(profile).loggingEntry.message": (message, { magenta }) =>
611 mapLines(message, x => `<p> ${magenta(x)}`),
612 "loggingEntry(profileEnd).loggingEntry.message": (message, { magenta }) =>
613 mapLines(message, x => `</p> ${magenta(x)}`),
614 "loggingEntry(time).loggingEntry.message": (message, { magenta }) =>
615 mapLines(message, x => `<t> ${magenta(x)}`),
616 "loggingEntry(group).loggingEntry.message": (message, { cyan }) =>
617 mapLines(message, x => `<-> ${cyan(x)}`),
618 "loggingEntry(groupCollapsed).loggingEntry.message": (message, { cyan }) =>
619 mapLines(message, x => `<+> ${cyan(x)}`),
620 "loggingEntry(clear).loggingEntry": () => " -------",
621 "loggingEntry(groupCollapsed).loggingEntry.children": () => "",
622 "loggingEntry.trace[]": trace =>
623 trace ? mapLines(trace, x => `| ${x}`) : undefined,
624
625 "moduleTraceItem.originName": originName => originName,
626
627 loggingGroup: loggingGroup =>
628 loggingGroup.entries.length === 0 ? "" : undefined,
629 "loggingGroup.debug": (flag, { red }) => (flag ? red("DEBUG") : undefined),
630 "loggingGroup.name": (name, { bold }) => bold(`LOG from ${name}`),
631 "loggingGroup.separator!": () => "\n",
632 "loggingGroup.filteredEntries": filteredEntries =>
633 filteredEntries > 0 ? `+ ${filteredEntries} hidden lines` : undefined,
634
635 "moduleTraceDependency.loc": loc => loc
636};
637
638/** @type {Record<string, string | Function>} */
639const ITEM_NAMES = {
640 "compilation.assets[]": "asset",
641 "compilation.modules[]": "module",
642 "compilation.chunks[]": "chunk",
643 "compilation.entrypoints[]": "chunkGroup",
644 "compilation.namedChunkGroups[]": "chunkGroup",
645 "compilation.errors[]": "error",
646 "compilation.warnings[]": "error",
647 "compilation.logging[]": "loggingGroup",
648 "compilation.children[]": "compilation",
649 "asset.related[]": "asset",
650 "asset.children[]": "asset",
651 "asset.chunks[]": "assetChunk",
652 "asset.auxiliaryChunks[]": "assetChunk",
653 "asset.chunkNames[]": "assetChunkName",
654 "asset.chunkIdHints[]": "assetChunkIdHint",
655 "asset.auxiliaryChunkNames[]": "assetChunkName",
656 "asset.auxiliaryChunkIdHints[]": "assetChunkIdHint",
657 "chunkGroup.assets[]": "chunkGroupAsset",
658 "chunkGroup.auxiliaryAssets[]": "chunkGroupAsset",
659 "chunkGroupChild.assets[]": "chunkGroupAsset",
660 "chunkGroupChild.auxiliaryAssets[]": "chunkGroupAsset",
661 "chunkGroup.children[]": "chunkGroupChildGroup",
662 "chunkGroupChildGroup.children[]": "chunkGroupChild",
663 "module.modules[]": "module",
664 "module.children[]": "module",
665 "module.reasons[]": "moduleReason",
666 "moduleReason.children[]": "moduleReason",
667 "module.issuerPath[]": "moduleIssuer",
668 "chunk.origins[]": "chunkOrigin",
669 "chunk.modules[]": "module",
670 "loggingGroup.entries[]": logEntry =>
671 `loggingEntry(${logEntry.type}).loggingEntry`,
672 "loggingEntry.children[]": logEntry =>
673 `loggingEntry(${logEntry.type}).loggingEntry`,
674 "error.moduleTrace[]": "moduleTraceItem",
675 "moduleTraceItem.dependencies[]": "moduleTraceDependency"
676};
677
678const ERROR_PREFERRED_ORDER = [
679 "compilerPath",
680 "chunkId",
681 "chunkEntry",
682 "chunkInitial",
683 "file",
684 "separator!",
685 "moduleName",
686 "loc",
687 "separator!",
688 "message",
689 "separator!",
690 "details",
691 "separator!",
692 "stack",
693 "separator!",
694 "missing",
695 "separator!",
696 "moduleTrace"
697];
698
699/** @type {Record<string, string[]>} */
700const PREFERRED_ORDERS = {
701 compilation: [
702 "name",
703 "hash",
704 "version",
705 "time",
706 "builtAt",
707 "env",
708 "publicPath",
709 "assets",
710 "filteredAssets",
711 "entrypoints",
712 "namedChunkGroups",
713 "chunks",
714 "modules",
715 "filteredModules",
716 "children",
717 "logging",
718 "warnings",
719 "warningsInChildren!",
720 "filteredWarningDetailsCount",
721 "errors",
722 "errorsInChildren!",
723 "filteredErrorDetailsCount",
724 "summary!",
725 "needAdditionalPass"
726 ],
727 asset: [
728 "type",
729 "name",
730 "size",
731 "chunks",
732 "auxiliaryChunks",
733 "emitted",
734 "comparedForEmit",
735 "cached",
736 "info",
737 "isOverSizeLimit",
738 "chunkNames",
739 "auxiliaryChunkNames",
740 "chunkIdHints",
741 "auxiliaryChunkIdHints",
742 "related",
743 "filteredRelated",
744 "children",
745 "filteredChildren"
746 ],
747 "asset.info": [
748 "immutable",
749 "sourceFilename",
750 "javascriptModule",
751 "development",
752 "hotModuleReplacement"
753 ],
754 chunkGroup: [
755 "kind!",
756 "name",
757 "isOverSizeLimit",
758 "assetsSize",
759 "auxiliaryAssetsSize",
760 "is!",
761 "assets",
762 "filteredAssets",
763 "auxiliaryAssets",
764 "filteredAuxiliaryAssets",
765 "separator!",
766 "children"
767 ],
768 chunkGroupAsset: ["name", "size"],
769 chunkGroupChildGroup: ["type", "children"],
770 chunkGroupChild: ["assets", "chunks", "name"],
771 module: [
772 "type",
773 "name",
774 "identifier",
775 "id",
776 "layer",
777 "sizes",
778 "chunks",
779 "depth",
780 "cacheable",
781 "orphan",
782 "runtime",
783 "optional",
784 "dependent",
785 "built",
786 "codeGenerated",
787 "cached",
788 "assets",
789 "failed",
790 "warnings",
791 "errors",
792 "children",
793 "filteredChildren",
794 "providedExports",
795 "usedExports",
796 "optimizationBailout",
797 "reasons",
798 "filteredReasons",
799 "issuerPath",
800 "profile",
801 "modules",
802 "filteredModules"
803 ],
804 moduleReason: [
805 "active",
806 "type",
807 "userRequest",
808 "moduleId",
809 "module",
810 "resolvedModule",
811 "loc",
812 "explanation",
813 "children",
814 "filteredChildren"
815 ],
816 "module.profile": [
817 "total",
818 "separator!",
819 "resolving",
820 "restoring",
821 "integration",
822 "building",
823 "storing",
824 "additionalResolving",
825 "additionalIntegration"
826 ],
827 chunk: [
828 "id",
829 "runtime",
830 "files",
831 "names",
832 "idHints",
833 "sizes",
834 "parents",
835 "siblings",
836 "children",
837 "childrenByOrder",
838 "entry",
839 "initial",
840 "rendered",
841 "recorded",
842 "reason",
843 "separator!",
844 "origins",
845 "separator!",
846 "modules",
847 "separator!",
848 "filteredModules"
849 ],
850 chunkOrigin: ["request", "moduleId", "moduleName", "loc"],
851 error: ERROR_PREFERRED_ORDER,
852 warning: ERROR_PREFERRED_ORDER,
853 "chunk.childrenByOrder[]": ["type", "children"],
854 loggingGroup: [
855 "debug",
856 "name",
857 "separator!",
858 "entries",
859 "separator!",
860 "filteredEntries"
861 ],
862 loggingEntry: ["message", "trace", "children"]
863};
864
865const itemsJoinOneLine = items => items.filter(Boolean).join(" ");
866const itemsJoinOneLineBrackets = items =>
867 items.length > 0 ? `(${items.filter(Boolean).join(" ")})` : undefined;
868const itemsJoinMoreSpacing = items => items.filter(Boolean).join("\n\n");
869const itemsJoinComma = items => items.filter(Boolean).join(", ");
870const itemsJoinCommaBrackets = items =>
871 items.length > 0 ? `(${items.filter(Boolean).join(", ")})` : undefined;
872const itemsJoinCommaBracketsWithName = name => items =>
873 items.length > 0
874 ? `(${name}: ${items.filter(Boolean).join(", ")})`
875 : undefined;
876
877/** @type {Record<string, (items: string[]) => string>} */
878const SIMPLE_ITEMS_JOINER = {
879 "chunk.parents": itemsJoinOneLine,
880 "chunk.siblings": itemsJoinOneLine,
881 "chunk.children": itemsJoinOneLine,
882 "chunk.names": itemsJoinCommaBrackets,
883 "chunk.idHints": itemsJoinCommaBracketsWithName("id hint"),
884 "chunk.runtime": itemsJoinCommaBracketsWithName("runtime"),
885 "chunk.files": itemsJoinComma,
886 "chunk.childrenByOrder": itemsJoinOneLine,
887 "chunk.childrenByOrder[].children": itemsJoinOneLine,
888 "chunkGroup.assets": itemsJoinOneLine,
889 "chunkGroup.auxiliaryAssets": itemsJoinOneLineBrackets,
890 "chunkGroupChildGroup.children": itemsJoinComma,
891 "chunkGroupChild.assets": itemsJoinOneLine,
892 "chunkGroupChild.auxiliaryAssets": itemsJoinOneLineBrackets,
893 "asset.chunks": itemsJoinComma,
894 "asset.auxiliaryChunks": itemsJoinCommaBrackets,
895 "asset.chunkNames": itemsJoinCommaBracketsWithName("name"),
896 "asset.auxiliaryChunkNames": itemsJoinCommaBracketsWithName("auxiliary name"),
897 "asset.chunkIdHints": itemsJoinCommaBracketsWithName("id hint"),
898 "asset.auxiliaryChunkIdHints":
899 itemsJoinCommaBracketsWithName("auxiliary id hint"),
900 "module.chunks": itemsJoinOneLine,
901 "module.issuerPath": items =>
902 items
903 .filter(Boolean)
904 .map(item => `${item} ->`)
905 .join(" "),
906 "compilation.errors": itemsJoinMoreSpacing,
907 "compilation.warnings": itemsJoinMoreSpacing,
908 "compilation.logging": itemsJoinMoreSpacing,
909 "compilation.children": items => indent(itemsJoinMoreSpacing(items), " "),
910 "moduleTraceItem.dependencies": itemsJoinOneLine,
911 "loggingEntry.children": items =>
912 indent(items.filter(Boolean).join("\n"), " ", false)
913};
914
915const joinOneLine = items =>
916 items
917 .map(item => item.content)
918 .filter(Boolean)
919 .join(" ");
920
921const joinInBrackets = items => {
922 const res = [];
923 let mode = 0;
924 for (const item of items) {
925 if (item.element === "separator!") {
926 switch (mode) {
927 case 0:
928 case 1:
929 mode += 2;
930 break;
931 case 4:
932 res.push(")");
933 mode = 3;
934 break;
935 }
936 }
937 if (!item.content) continue;
938 switch (mode) {
939 case 0:
940 mode = 1;
941 break;
942 case 1:
943 res.push(" ");
944 break;
945 case 2:
946 res.push("(");
947 mode = 4;
948 break;
949 case 3:
950 res.push(" (");
951 mode = 4;
952 break;
953 case 4:
954 res.push(", ");
955 break;
956 }
957 res.push(item.content);
958 }
959 if (mode === 4) res.push(")");
960 return res.join("");
961};
962
963const indent = (str, prefix, noPrefixInFirstLine) => {
964 const rem = str.replace(/\n([^\n])/g, "\n" + prefix + "$1");
965 if (noPrefixInFirstLine) return rem;
966 const ind = str[0] === "\n" ? "" : prefix;
967 return ind + rem;
968};
969
970const joinExplicitNewLine = (items, indenter) => {
971 let firstInLine = true;
972 let first = true;
973 return items
974 .map(item => {
975 if (!item || !item.content) return;
976 let content = indent(item.content, first ? "" : indenter, !firstInLine);
977 if (firstInLine) {
978 content = content.replace(/^\n+/, "");
979 }
980 if (!content) return;
981 first = false;
982 const noJoiner = firstInLine || content.startsWith("\n");
983 firstInLine = content.endsWith("\n");
984 return noJoiner ? content : " " + content;
985 })
986 .filter(Boolean)
987 .join("")
988 .trim();
989};
990
991const joinError =
992 error =>
993 (items, { red, yellow }) =>
994 `${error ? red("ERROR") : yellow("WARNING")} in ${joinExplicitNewLine(
995 items,
996 ""
997 )}`;
998
999/** @type {Record<string, (items: ({ element: string, content: string })[], context: StatsPrinterContext) => string>} */
1000const SIMPLE_ELEMENT_JOINERS = {
1001 compilation: items => {
1002 const result = [];
1003 let lastNeedMore = false;
1004 for (const item of items) {
1005 if (!item.content) continue;
1006 const needMoreSpace =
1007 item.element === "warnings" ||
1008 item.element === "filteredWarningDetailsCount" ||
1009 item.element === "errors" ||
1010 item.element === "filteredErrorDetailsCount" ||
1011 item.element === "logging";
1012 if (result.length !== 0) {
1013 result.push(needMoreSpace || lastNeedMore ? "\n\n" : "\n");
1014 }
1015 result.push(item.content);
1016 lastNeedMore = needMoreSpace;
1017 }
1018 if (lastNeedMore) result.push("\n");
1019 return result.join("");
1020 },
1021 asset: items =>
1022 joinExplicitNewLine(
1023 items.map(item => {
1024 if (
1025 (item.element === "related" || item.element === "children") &&
1026 item.content
1027 ) {
1028 return {
1029 ...item,
1030 content: `\n${item.content}\n`
1031 };
1032 }
1033 return item;
1034 }),
1035 " "
1036 ),
1037 "asset.info": joinOneLine,
1038 module: (items, { module }) => {
1039 let hasName = false;
1040 return joinExplicitNewLine(
1041 items.map(item => {
1042 switch (item.element) {
1043 case "id":
1044 if (module.id === module.name) {
1045 if (hasName) return false;
1046 if (item.content) hasName = true;
1047 }
1048 break;
1049 case "name":
1050 if (hasName) return false;
1051 if (item.content) hasName = true;
1052 break;
1053 case "providedExports":
1054 case "usedExports":
1055 case "optimizationBailout":
1056 case "reasons":
1057 case "issuerPath":
1058 case "profile":
1059 case "children":
1060 case "modules":
1061 if (item.content) {
1062 return {
1063 ...item,
1064 content: `\n${item.content}\n`
1065 };
1066 }
1067 break;
1068 }
1069 return item;
1070 }),
1071 " "
1072 );
1073 },
1074 chunk: items => {
1075 let hasEntry = false;
1076 return (
1077 "chunk " +
1078 joinExplicitNewLine(
1079 items.filter(item => {
1080 switch (item.element) {
1081 case "entry":
1082 if (item.content) hasEntry = true;
1083 break;
1084 case "initial":
1085 if (hasEntry) return false;
1086 break;
1087 }
1088 return true;
1089 }),
1090 " "
1091 )
1092 );
1093 },
1094 "chunk.childrenByOrder[]": items => `(${joinOneLine(items)})`,
1095 chunkGroup: items => joinExplicitNewLine(items, " "),
1096 chunkGroupAsset: joinOneLine,
1097 chunkGroupChildGroup: joinOneLine,
1098 chunkGroupChild: joinOneLine,
1099 // moduleReason: (items, { moduleReason }) => {
1100 // let hasName = false;
1101 // return joinOneLine(
1102 // items.filter(item => {
1103 // switch (item.element) {
1104 // case "moduleId":
1105 // if (moduleReason.moduleId === moduleReason.module && item.content)
1106 // hasName = true;
1107 // break;
1108 // case "module":
1109 // if (hasName) return false;
1110 // break;
1111 // case "resolvedModule":
1112 // return (
1113 // moduleReason.module !== moduleReason.resolvedModule &&
1114 // item.content
1115 // );
1116 // }
1117 // return true;
1118 // })
1119 // );
1120 // },
1121 moduleReason: (items, { moduleReason }) => {
1122 let hasName = false;
1123 return joinExplicitNewLine(
1124 items.map(item => {
1125 switch (item.element) {
1126 case "moduleId":
1127 if (moduleReason.moduleId === moduleReason.module && item.content)
1128 hasName = true;
1129 break;
1130 case "module":
1131 if (hasName) return false;
1132 break;
1133 case "resolvedModule":
1134 if (moduleReason.module === moduleReason.resolvedModule)
1135 return false;
1136 break;
1137 case "children":
1138 if (item.content) {
1139 return {
1140 ...item,
1141 content: `\n${item.content}\n`
1142 };
1143 }
1144 break;
1145 }
1146 return item;
1147 }),
1148 " "
1149 );
1150 },
1151 "module.profile": joinInBrackets,
1152 moduleIssuer: joinOneLine,
1153 chunkOrigin: items => "> " + joinOneLine(items),
1154 "errors[].error": joinError(true),
1155 "warnings[].error": joinError(false),
1156 loggingGroup: items => joinExplicitNewLine(items, "").trimRight(),
1157 moduleTraceItem: items => " @ " + joinOneLine(items),
1158 moduleTraceDependency: joinOneLine
1159};
1160
1161const AVAILABLE_COLORS = {
1162 bold: "\u001b[1m",
1163 yellow: "\u001b[1m\u001b[33m",
1164 red: "\u001b[1m\u001b[31m",
1165 green: "\u001b[1m\u001b[32m",
1166 cyan: "\u001b[1m\u001b[36m",
1167 magenta: "\u001b[1m\u001b[35m"
1168};
1169
1170const AVAILABLE_FORMATS = {
1171 formatChunkId: (id, { yellow }, direction) => {
1172 switch (direction) {
1173 case "parent":
1174 return `<{${yellow(id)}}>`;
1175 case "sibling":
1176 return `={${yellow(id)}}=`;
1177 case "child":
1178 return `>{${yellow(id)}}<`;
1179 default:
1180 return `{${yellow(id)}}`;
1181 }
1182 },
1183 formatModuleId: id => `[${id}]`,
1184 formatFilename: (filename, { green, yellow }, oversize) =>
1185 (oversize ? yellow : green)(filename),
1186 formatFlag: flag => `[${flag}]`,
1187 formatLayer: layer => `(in ${layer})`,
1188 formatSize: require("../SizeFormatHelpers").formatSize,
1189 formatDateTime: (dateTime, { bold }) => {
1190 const d = new Date(dateTime);
1191 const x = twoDigit;
1192 const date = `${d.getFullYear()}-${x(d.getMonth() + 1)}-${x(d.getDate())}`;
1193 const time = `${x(d.getHours())}:${x(d.getMinutes())}:${x(d.getSeconds())}`;
1194 return `${date} ${bold(time)}`;
1195 },
1196 formatTime: (
1197 time,
1198 { timeReference, bold, green, yellow, red },
1199 boldQuantity
1200 ) => {
1201 const unit = " ms";
1202 if (timeReference && time !== timeReference) {
1203 const times = [
1204 timeReference / 2,
1205 timeReference / 4,
1206 timeReference / 8,
1207 timeReference / 16
1208 ];
1209 if (time < times[3]) return `${time}${unit}`;
1210 else if (time < times[2]) return bold(`${time}${unit}`);
1211 else if (time < times[1]) return green(`${time}${unit}`);
1212 else if (time < times[0]) return yellow(`${time}${unit}`);
1213 else return red(`${time}${unit}`);
1214 } else {
1215 return `${boldQuantity ? bold(time) : time}${unit}`;
1216 }
1217 },
1218 formatError: (message, { green, yellow, red }) => {
1219 if (message.includes("\u001b[")) return message;
1220 const highlights = [
1221 { regExp: /(Did you mean .+)/g, format: green },
1222 {
1223 regExp: /(Set 'mode' option to 'development' or 'production')/g,
1224 format: green
1225 },
1226 { regExp: /(\(module has no exports\))/g, format: red },
1227 { regExp: /\(possible exports: (.+)\)/g, format: green },
1228 { regExp: /(?:^|\n)(.* doesn't exist)/g, format: red },
1229 { regExp: /('\w+' option has not been set)/g, format: red },
1230 {
1231 regExp: /(Emitted value instead of an instance of Error)/g,
1232 format: yellow
1233 },
1234 { regExp: /(Used? .+ instead)/gi, format: yellow },
1235 { regExp: /\b(deprecated|must|required)\b/g, format: yellow },
1236 {
1237 regExp: /\b(BREAKING CHANGE)\b/gi,
1238 format: red
1239 },
1240 {
1241 regExp:
1242 /\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,
1243 format: red
1244 }
1245 ];
1246 for (const { regExp, format } of highlights) {
1247 message = message.replace(regExp, (match, content) => {
1248 return match.replace(content, format(content));
1249 });
1250 }
1251 return message;
1252 }
1253};
1254
1255const RESULT_MODIFIER = {
1256 "module.modules": result => {
1257 return indent(result, "| ");
1258 }
1259};
1260
1261const createOrder = (array, preferredOrder) => {
1262 const originalArray = array.slice();
1263 const set = new Set(array);
1264 const usedSet = new Set();
1265 array.length = 0;
1266 for (const element of preferredOrder) {
1267 if (element.endsWith("!") || set.has(element)) {
1268 array.push(element);
1269 usedSet.add(element);
1270 }
1271 }
1272 for (const element of originalArray) {
1273 if (!usedSet.has(element)) {
1274 array.push(element);
1275 }
1276 }
1277 return array;
1278};
1279
1280class DefaultStatsPrinterPlugin {
1281 /**
1282 * Apply the plugin
1283 * @param {Compiler} compiler the compiler instance
1284 * @returns {void}
1285 */
1286 apply(compiler) {
1287 compiler.hooks.compilation.tap("DefaultStatsPrinterPlugin", compilation => {
1288 compilation.hooks.statsPrinter.tap(
1289 "DefaultStatsPrinterPlugin",
1290 (stats, options, context) => {
1291 // Put colors into context
1292 stats.hooks.print
1293 .for("compilation")
1294 .tap("DefaultStatsPrinterPlugin", (compilation, context) => {
1295 for (const color of Object.keys(AVAILABLE_COLORS)) {
1296 let start;
1297 if (options.colors) {
1298 if (
1299 typeof options.colors === "object" &&
1300 typeof options.colors[color] === "string"
1301 ) {
1302 start = options.colors[color];
1303 } else {
1304 start = AVAILABLE_COLORS[color];
1305 }
1306 }
1307 if (start) {
1308 context[color] = str =>
1309 `${start}${
1310 typeof str === "string"
1311 ? str.replace(
1312 /((\u001b\[39m|\u001b\[22m|\u001b\[0m)+)/g,
1313 `$1${start}`
1314 )
1315 : str
1316 }\u001b[39m\u001b[22m`;
1317 } else {
1318 context[color] = str => str;
1319 }
1320 }
1321 for (const format of Object.keys(AVAILABLE_FORMATS)) {
1322 context[format] = (content, ...args) =>
1323 AVAILABLE_FORMATS[format](content, context, ...args);
1324 }
1325 context.timeReference = compilation.time;
1326 });
1327
1328 for (const key of Object.keys(SIMPLE_PRINTERS)) {
1329 stats.hooks.print
1330 .for(key)
1331 .tap("DefaultStatsPrinterPlugin", (obj, ctx) =>
1332 SIMPLE_PRINTERS[key](obj, ctx, stats)
1333 );
1334 }
1335
1336 for (const key of Object.keys(PREFERRED_ORDERS)) {
1337 const preferredOrder = PREFERRED_ORDERS[key];
1338 stats.hooks.sortElements
1339 .for(key)
1340 .tap("DefaultStatsPrinterPlugin", (elements, context) => {
1341 createOrder(elements, preferredOrder);
1342 });
1343 }
1344
1345 for (const key of Object.keys(ITEM_NAMES)) {
1346 const itemName = ITEM_NAMES[key];
1347 stats.hooks.getItemName
1348 .for(key)
1349 .tap(
1350 "DefaultStatsPrinterPlugin",
1351 typeof itemName === "string" ? () => itemName : itemName
1352 );
1353 }
1354
1355 for (const key of Object.keys(SIMPLE_ITEMS_JOINER)) {
1356 const joiner = SIMPLE_ITEMS_JOINER[key];
1357 stats.hooks.printItems
1358 .for(key)
1359 .tap("DefaultStatsPrinterPlugin", joiner);
1360 }
1361
1362 for (const key of Object.keys(SIMPLE_ELEMENT_JOINERS)) {
1363 const joiner = SIMPLE_ELEMENT_JOINERS[key];
1364 stats.hooks.printElements
1365 .for(key)
1366 .tap("DefaultStatsPrinterPlugin", joiner);
1367 }
1368
1369 for (const key of Object.keys(RESULT_MODIFIER)) {
1370 const modifier = RESULT_MODIFIER[key];
1371 stats.hooks.result
1372 .for(key)
1373 .tap("DefaultStatsPrinterPlugin", modifier);
1374 }
1375 }
1376 );
1377 });
1378 }
1379}
1380module.exports = DefaultStatsPrinterPlugin;