source: imaps-frontend/node_modules/webpack/lib/stats/DefaultStatsPrinterPlugin.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

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