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

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

Fix frontend appearance

  • Property mode set to 100644
File size: 86.5 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
8const util = require("util");
9const { WEBPACK_MODULE_TYPE_RUNTIME } = require("../ModuleTypeConstants");
10const ModuleDependency = require("../dependencies/ModuleDependency");
11const { LogType } = require("../logging/Logger");
12const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
13const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin");
14const { countIterable } = require("../util/IterableHelpers");
15const {
16 compareChunksById,
17 compareIds,
18 compareLocations,
19 compareModulesByIdentifier,
20 compareNumbers,
21 compareSelect,
22 concatComparators
23} = require("../util/comparators");
24const formatLocation = require("../util/formatLocation");
25const { makePathsRelative, parseResource } = require("../util/identifier");
26
27/** @typedef {import("webpack-sources").Source} Source */
28/** @typedef {import("../../declarations/WebpackOptions").StatsValue} StatsValue */
29/** @typedef {import("./StatsFactory")} StatsFactory */
30/** @typedef {import("./StatsFactory").StatsFactoryContext} StatsFactoryContext */
31/** @typedef {import("../Chunk")} Chunk */
32/** @typedef {import("../Chunk").ChunkId} ChunkId */
33/** @typedef {import("../Chunk").ChunkName} ChunkName */
34/** @typedef {import("../ChunkGraph").ModuleId} ModuleId */
35/** @typedef {import("../ChunkGroup")} ChunkGroup */
36/** @typedef {import("../ChunkGroup").OriginRecord} OriginRecord */
37/** @typedef {import("../Compilation")} Compilation */
38/** @typedef {import("../Compilation").Asset} Asset */
39/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
40/** @typedef {import("../Compilation").ExcludeModulesType} ExcludeModulesType */
41/** @typedef {import("../Compilation").KnownNormalizedStatsOptions} KnownNormalizedStatsOptions */
42/** @typedef {import("../Compilation").NormalizedStatsOptions} NormalizedStatsOptions */
43/** @typedef {import("../Compiler")} Compiler */
44/** @typedef {import("../Dependency")} Dependency */
45/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
46/** @typedef {import("../Module")} Module */
47/** @typedef {import("../Module").NameForCondition} NameForCondition */
48/** @typedef {import("../Module").BuildInfo} BuildInfo */
49/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
50/** @typedef {import("../ModuleProfile")} ModuleProfile */
51/** @typedef {import("../errors/WebpackError")} WebpackError */
52/** @typedef {import("../serialization/AggregateErrorSerializer").AggregateError} AggregateError */
53/** @typedef {import("../serialization/ErrorObjectSerializer").ErrorWithCause} ErrorWithCause */
54/** @typedef {import("../ExportsInfo").ExportInfoName} ExportInfoName */
55
56/**
57 * Defines the shared type used by this module.
58 * @template T
59 * @typedef {import("../util/comparators").Comparator<T>} Comparator<T>
60 */
61
62/**
63 * Defines the group config type used by this module.
64 * @template I, G
65 * @typedef {import("../util/smartGrouping").GroupConfig<I, G>} GroupConfig
66 */
67
68/** @typedef {KnownStatsCompilation & Record<string, EXPECTED_ANY>} StatsCompilation */
69/**
70 * Defines the known stats compilation type used by this module.
71 * @typedef {object} KnownStatsCompilation
72 * @property {EXPECTED_ANY=} env
73 * @property {string=} name
74 * @property {string=} hash
75 * @property {string=} version
76 * @property {number=} time
77 * @property {number=} builtAt
78 * @property {boolean=} needAdditionalPass
79 * @property {string=} publicPath
80 * @property {string=} outputPath
81 * @property {Record<string, string[]>=} assetsByChunkName
82 * @property {StatsAsset[]=} assets
83 * @property {number=} filteredAssets
84 * @property {StatsChunk[]=} chunks
85 * @property {StatsModule[]=} modules
86 * @property {number=} filteredModules
87 * @property {Record<string, StatsChunkGroup>=} entrypoints
88 * @property {Record<string, StatsChunkGroup>=} namedChunkGroups
89 * @property {StatsError[]=} errors
90 * @property {number=} errorsCount
91 * @property {StatsError[]=} warnings
92 * @property {number=} warningsCount
93 * @property {StatsCompilation[]=} children
94 * @property {Record<string, StatsLogging>=} logging
95 * @property {number=} filteredWarningDetailsCount
96 * @property {number=} filteredErrorDetailsCount
97 */
98
99/** @typedef {KnownStatsLogging & Record<string, EXPECTED_ANY>} StatsLogging */
100/**
101 * Defines the known stats logging type used by this module.
102 * @typedef {object} KnownStatsLogging
103 * @property {StatsLoggingEntry[]} entries
104 * @property {number} filteredEntries
105 * @property {boolean} debug
106 */
107
108/** @typedef {KnownStatsLoggingEntry & Record<string, EXPECTED_ANY>} StatsLoggingEntry */
109/**
110 * Defines the known stats logging entry type used by this module.
111 * @typedef {object} KnownStatsLoggingEntry
112 * @property {string} type
113 * @property {string=} message
114 * @property {string[]=} trace
115 * @property {StatsLoggingEntry[]=} children
116 * @property {EXPECTED_ANY[]=} args
117 * @property {number=} time
118 */
119
120/** @typedef {KnownStatsAsset & Record<string, EXPECTED_ANY>} StatsAsset */
121/** @typedef {string[]} ChunkIdHints */
122/**
123 * Defines the known stats asset type used by this module.
124 * @typedef {object} KnownStatsAsset
125 * @property {string} type
126 * @property {string} name
127 * @property {AssetInfo} info
128 * @property {number} size
129 * @property {boolean} emitted
130 * @property {boolean} comparedForEmit
131 * @property {boolean} cached
132 * @property {StatsAsset[]=} related
133 * @property {ChunkId[]=} chunks
134 * @property {ChunkName[]=} chunkNames
135 * @property {ChunkIdHints=} chunkIdHints
136 * @property {ChunkId[]=} auxiliaryChunks
137 * @property {ChunkName[]=} auxiliaryChunkNames
138 * @property {ChunkIdHints=} auxiliaryChunkIdHints
139 * @property {number=} filteredRelated
140 * @property {boolean=} isOverSizeLimit
141 */
142
143/** @typedef {KnownStatsChunkGroup & Record<string, EXPECTED_ANY>} StatsChunkGroup */
144/**
145 * Defines the known stats chunk group type used by this module.
146 * @typedef {object} KnownStatsChunkGroup
147 * @property {ChunkName=} name
148 * @property {ChunkId[]=} chunks
149 * @property {({ name: string, size?: number })[]=} assets
150 * @property {number=} filteredAssets
151 * @property {number=} assetsSize
152 * @property {({ name: string, size?: number })[]=} auxiliaryAssets
153 * @property {number=} filteredAuxiliaryAssets
154 * @property {number=} auxiliaryAssetsSize
155 * @property {Record<string, StatsChunkGroup[]>=} children
156 * @property {Record<string, string[]>=} childAssets
157 * @property {boolean=} isOverSizeLimit
158 */
159
160/** @typedef {Module[]} ModuleIssuerPath */
161/** @typedef {KnownStatsModule & Record<string, EXPECTED_ANY>} StatsModule */
162/**
163 * Defines the known stats module type used by this module.
164 * @typedef {object} KnownStatsModule
165 * @property {string=} type
166 * @property {string=} moduleType
167 * @property {(string | null)=} layer
168 * @property {string=} identifier
169 * @property {string=} name
170 * @property {NameForCondition | null=} nameForCondition
171 * @property {number=} index
172 * @property {number=} preOrderIndex
173 * @property {number=} index2
174 * @property {number=} postOrderIndex
175 * @property {number=} size
176 * @property {Record<string, number>=} sizes
177 * @property {boolean=} cacheable
178 * @property {boolean=} built
179 * @property {boolean=} codeGenerated
180 * @property {boolean=} buildTimeExecuted
181 * @property {boolean=} cached
182 * @property {boolean=} optional
183 * @property {boolean=} orphan
184 * @property {ModuleId=} id
185 * @property {ModuleId | null=} issuerId
186 * @property {ChunkId[]=} chunks
187 * @property {string[]=} assets
188 * @property {boolean=} dependent
189 * @property {(string | null)=} issuer
190 * @property {(string | null)=} issuerName
191 * @property {StatsModuleIssuer[] | null=} issuerPath
192 * @property {boolean=} failed
193 * @property {number=} errors
194 * @property {number=} warnings
195 * @property {StatsProfile=} profile
196 * @property {StatsModuleReason[]=} reasons
197 * @property {boolean | null | ExportInfoName[]=} usedExports
198 * @property {ExportInfoName[] | null=} providedExports
199 * @property {string[]=} optimizationBailout
200 * @property {(number | null)=} depth
201 * @property {StatsModule[]=} modules
202 * @property {number=} filteredModules
203 * @property {ReturnType<Source["source"]>=} source
204 */
205
206/** @typedef {KnownStatsProfile & Record<string, EXPECTED_ANY>} StatsProfile */
207/**
208 * Defines the known stats profile type used by this module.
209 * @typedef {object} KnownStatsProfile
210 * @property {number} total
211 * @property {number} resolving
212 * @property {number} restoring
213 * @property {number} building
214 * @property {number} integration
215 * @property {number} storing
216 * @property {number} additionalResolving
217 * @property {number} additionalIntegration
218 * @property {number} factory
219 * @property {number} dependencies
220 */
221
222/** @typedef {KnownStatsModuleIssuer & Record<string, EXPECTED_ANY>} StatsModuleIssuer */
223/**
224 * Defines the known stats module issuer type used by this module.
225 * @typedef {object} KnownStatsModuleIssuer
226 * @property {string} identifier
227 * @property {string} name
228 * @property {ModuleId=} id
229 * @property {StatsProfile} profile
230 */
231
232/** @typedef {KnownStatsModuleReason & Record<string, EXPECTED_ANY>} StatsModuleReason */
233/**
234 * Defines the known stats module reason type used by this module.
235 * @typedef {object} KnownStatsModuleReason
236 * @property {string | null} moduleIdentifier
237 * @property {string | null} module
238 * @property {string | null} moduleName
239 * @property {string | null} resolvedModuleIdentifier
240 * @property {string | null} resolvedModule
241 * @property {string | null} type
242 * @property {boolean} active
243 * @property {string | null} explanation
244 * @property {string | null} userRequest
245 * @property {(string | null)=} loc
246 * @property {ModuleId | null=} moduleId
247 * @property {ModuleId | null=} resolvedModuleId
248 */
249
250/** @typedef {KnownStatsChunk & Record<string, EXPECTED_ANY>} StatsChunk */
251/**
252 * Defines the known stats chunk type used by this module.
253 * @typedef {object} KnownStatsChunk
254 * @property {boolean} rendered
255 * @property {boolean} initial
256 * @property {boolean} entry
257 * @property {boolean} recorded
258 * @property {string=} reason
259 * @property {number} size
260 * @property {Record<string, number>} sizes
261 * @property {string[]} names
262 * @property {string[]} idHints
263 * @property {string[]=} runtime
264 * @property {string[]} files
265 * @property {string[]} auxiliaryFiles
266 * @property {string} hash
267 * @property {Record<string, ChunkId[]>} childrenByOrder
268 * @property {ChunkId=} id
269 * @property {ChunkId[]=} siblings
270 * @property {ChunkId[]=} parents
271 * @property {ChunkId[]=} children
272 * @property {StatsModule[]=} modules
273 * @property {number=} filteredModules
274 * @property {StatsChunkOrigin[]=} origins
275 */
276
277/** @typedef {KnownStatsChunkOrigin & Record<string, EXPECTED_ANY>} StatsChunkOrigin */
278/**
279 * Defines the known stats chunk origin type used by this module.
280 * @typedef {object} KnownStatsChunkOrigin
281 * @property {string} module
282 * @property {string} moduleIdentifier
283 * @property {string} moduleName
284 * @property {string} loc
285 * @property {string} request
286 * @property {ModuleId=} moduleId
287 */
288
289/** @typedef {KnownStatsModuleTraceItem & Record<string, EXPECTED_ANY>} StatsModuleTraceItem */
290/**
291 * Defines the known stats module trace item type used by this module.
292 * @typedef {object} KnownStatsModuleTraceItem
293 * @property {string=} originIdentifier
294 * @property {string=} originName
295 * @property {string=} moduleIdentifier
296 * @property {string=} moduleName
297 * @property {StatsModuleTraceDependency[]=} dependencies
298 * @property {ModuleId=} originId
299 * @property {ModuleId=} moduleId
300 */
301
302/** @typedef {KnownStatsModuleTraceDependency & Record<string, EXPECTED_ANY>} StatsModuleTraceDependency */
303/**
304 * Defines the known stats module trace dependency type used by this module.
305 * @typedef {object} KnownStatsModuleTraceDependency
306 * @property {string=} loc
307 */
308
309/** @typedef {KnownStatsError & Record<string, EXPECTED_ANY>} StatsError */
310/**
311 * Defines the known stats error type used by this module.
312 * @typedef {object} KnownStatsError
313 * @property {string} message
314 * @property {string=} chunkName
315 * @property {boolean=} chunkEntry
316 * @property {boolean=} chunkInitial
317 * @property {string=} file
318 * @property {string=} moduleIdentifier
319 * @property {string=} moduleName
320 * @property {string=} loc
321 * @property {ChunkId=} chunkId
322 * @property {ModuleId=} moduleId
323 * @property {StatsModuleTraceItem[]=} moduleTrace
324 * @property {string=} details
325 * @property {string=} stack
326 * @property {KnownStatsError=} cause
327 * @property {KnownStatsError[]=} errors
328 * @property {string=} compilerPath
329 */
330
331/** @typedef {Asset & { type: string, related: PreprocessedAsset[] | undefined }} PreprocessedAsset */
332
333/**
334 * Defines the extractors by option type used by this module.
335 * @template T
336 * @template O
337 * @typedef {Record<string, (object: O, data: T, context: StatsFactoryContext, options: NormalizedStatsOptions, factory: StatsFactory) => void>} ExtractorsByOption
338 */
339
340/** @typedef {{ name: string, chunkGroup: ChunkGroup }} ChunkGroupInfoWithName */
341/** @typedef {{ origin: Module, module: Module }} ModuleTrace */
342
343/**
344 * Defines the simple extractors type used by this module.
345 * @typedef {object} SimpleExtractors
346 * @property {ExtractorsByOption<Compilation, StatsCompilation>} compilation
347 * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset
348 * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset$visible
349 * @property {ExtractorsByOption<ChunkGroupInfoWithName, StatsChunkGroup>} chunkGroup
350 * @property {ExtractorsByOption<Module, StatsModule>} module
351 * @property {ExtractorsByOption<Module, StatsModule>} module$visible
352 * @property {ExtractorsByOption<Module, StatsModuleIssuer>} moduleIssuer
353 * @property {ExtractorsByOption<ModuleProfile, StatsProfile>} profile
354 * @property {ExtractorsByOption<ModuleGraphConnection, StatsModuleReason>} moduleReason
355 * @property {ExtractorsByOption<Chunk, StatsChunk>} chunk
356 * @property {ExtractorsByOption<OriginRecord, StatsChunkOrigin>} chunkOrigin
357 * @property {ExtractorsByOption<WebpackError, StatsError>} error
358 * @property {ExtractorsByOption<WebpackError, StatsError>} warning
359 * @property {ExtractorsByOption<WebpackError, StatsError>} cause
360 * @property {ExtractorsByOption<ModuleTrace, StatsModuleTraceItem>} moduleTraceItem
361 * @property {ExtractorsByOption<Dependency, StatsModuleTraceDependency>} moduleTraceDependency
362 */
363
364/**
365 * Returns array of values.
366 * @template T
367 * @template I
368 * @param {Iterable<T>} items items to select from
369 * @param {(item: T) => Iterable<I>} selector selector function to select values from item
370 * @returns {I[]} array of values
371 */
372const uniqueArray = (items, selector) => {
373 /** @type {Set<I>} */
374 const set = new Set();
375 for (const item of items) {
376 for (const i of selector(item)) {
377 set.add(i);
378 }
379 }
380 return [...set];
381};
382
383/**
384 * Unique ordered array.
385 * @template T
386 * @template I
387 * @param {Iterable<T>} items items to select from
388 * @param {(item: T) => Iterable<I>} selector selector function to select values from item
389 * @param {Comparator<I>} comparator comparator function
390 * @returns {I[]} array of values
391 */
392const uniqueOrderedArray = (items, selector, comparator) =>
393 uniqueArray(items, selector).sort(comparator);
394
395/**
396 * Defines the shared type used by this module.
397 * @template T
398 * @template R
399 * @typedef {{ [P in keyof T]: R }} MappedValues<T, R>
400 */
401
402/**
403 * Returns mapped object.
404 * @template {object} T
405 * @template {object} R
406 * @param {T} obj object to be mapped
407 * @param {(value: T[keyof T], key: keyof T) => R} fn mapping function
408 * @returns {MappedValues<T, R>} mapped object
409 */
410const mapObject = (obj, fn) => {
411 /** @type {MappedValues<T, R>} */
412 const newObj = Object.create(null);
413 for (const key of /** @type {(keyof T)[]} */ (Object.keys(obj))) {
414 newObj[key] = fn(obj[key], key);
415 }
416 return newObj;
417};
418
419/**
420 * Count with children.
421 * @template T
422 * @param {Compilation} compilation the compilation
423 * @param {(compilation: Compilation, name: string) => T[]} getItems get items
424 * @returns {number} total number
425 */
426const countWithChildren = (compilation, getItems) => {
427 let count = getItems(compilation, "").length;
428 for (const child of compilation.children) {
429 count += countWithChildren(child, (c, type) =>
430 getItems(c, `.children[].compilation${type}`)
431 );
432 }
433 return count;
434};
435
436/** @type {ExtractorsByOption<string | ErrorWithCause | AggregateError | WebpackError, StatsError>} */
437const EXTRACT_ERROR = {
438 _: (object, error, context, { requestShortener }) => {
439 // TODO webpack 6 disallow strings in the errors/warnings list
440 if (typeof error === "string") {
441 object.message = error;
442 } else {
443 if (/** @type {WebpackError} */ (error).chunk) {
444 const chunk = /** @type {WebpackError} */ (error).chunk;
445 object.chunkName =
446 /** @type {string | undefined} */
447 (chunk.name);
448 object.chunkEntry = chunk.hasRuntime();
449 object.chunkInitial = chunk.canBeInitial();
450 }
451
452 if (/** @type {WebpackError} */ (error).file) {
453 object.file = /** @type {WebpackError} */ (error).file;
454 }
455
456 if (/** @type {WebpackError} */ (error).module) {
457 object.moduleIdentifier =
458 /** @type {WebpackError} */
459 (error).module.identifier();
460 object.moduleName =
461 /** @type {WebpackError} */
462 (error).module.readableIdentifier(requestShortener);
463 }
464
465 if (/** @type {WebpackError} */ (error).loc) {
466 object.loc = formatLocation(/** @type {WebpackError} */ (error).loc);
467 }
468
469 object.message = error.message;
470 }
471 },
472 ids: (object, error, { compilation: { chunkGraph } }) => {
473 if (typeof error !== "string") {
474 if (/** @type {WebpackError} */ (error).chunk) {
475 object.chunkId = /** @type {ChunkId} */ (
476 /** @type {WebpackError} */
477 (error).chunk.id
478 );
479 }
480
481 if (/** @type {WebpackError} */ (error).module) {
482 object.moduleId =
483 /** @type {ModuleId} */
484 (chunkGraph.getModuleId(/** @type {WebpackError} */ (error).module));
485 }
486 }
487 },
488 moduleTrace: (object, error, context, options, factory) => {
489 if (
490 typeof error !== "string" &&
491 /** @type {WebpackError} */ (error).module
492 ) {
493 const {
494 type,
495 compilation: { moduleGraph }
496 } = context;
497 /** @type {Set<Module>} */
498 const visitedModules = new Set();
499 /** @type {ModuleTrace[]} */
500 const moduleTrace = [];
501 let current = /** @type {WebpackError} */ (error).module;
502 while (current) {
503 if (visitedModules.has(current)) break; // circular (technically impossible, but how knows)
504 visitedModules.add(current);
505 const origin = moduleGraph.getIssuer(current);
506 if (!origin) break;
507 moduleTrace.push({ origin, module: current });
508 current = origin;
509 }
510 object.moduleTrace = factory.create(
511 `${type}.moduleTrace`,
512 moduleTrace,
513 context
514 );
515 }
516 },
517 errorDetails: (
518 object,
519 error,
520 { type, compilation, cachedGetErrors },
521 { errorDetails }
522 ) => {
523 if (
524 typeof error !== "string" &&
525 (errorDetails === true ||
526 (type.endsWith(".error") && cachedGetErrors(compilation).length < 3))
527 ) {
528 object.details = /** @type {WebpackError} */ (error).details;
529 }
530 },
531 errorStack: (object, error, _context, { errorStack }) => {
532 if (typeof error !== "string" && errorStack) {
533 object.stack = error.stack;
534 }
535 },
536 errorCause: (object, error, context, options, factory) => {
537 if (
538 typeof error !== "string" &&
539 /** @type {ErrorWithCause} */ (error).cause
540 ) {
541 const rawCause = /** @type {ErrorWithCause} */ (error).cause;
542 /** @type {Error} */
543 const cause =
544 typeof rawCause === "string"
545 ? /** @type {Error} */ ({ message: rawCause })
546 : /** @type {Error} */ (rawCause);
547 const { type } = context;
548
549 object.cause = factory.create(`${type}.cause`, cause, context);
550 }
551 },
552 errorErrors: (object, error, context, options, factory) => {
553 if (
554 typeof error !== "string" &&
555 /** @type {AggregateError} */
556 (error).errors
557 ) {
558 const { type } = context;
559 object.errors = factory.create(
560 `${type}.errors`,
561 /** @type {Error[]} */
562 (/** @type {AggregateError} */ (error).errors),
563 context
564 );
565 }
566 }
567};
568
569/** @typedef {((value: string) => boolean)} FilterItemTypeFn */
570
571/** @type {SimpleExtractors} */
572const SIMPLE_EXTRACTORS = {
573 compilation: {
574 _: (object, compilation, context, options) => {
575 if (!context.makePathsRelative) {
576 context.makePathsRelative = makePathsRelative.bindContextCache(
577 compilation.compiler.context,
578 compilation.compiler.root
579 );
580 }
581 if (!context.cachedGetErrors) {
582 /** @type {WeakMap<Compilation, Error[]>} */
583 const map = new WeakMap();
584 context.cachedGetErrors = (compilation) =>
585 map.get(compilation) ||
586 // eslint-disable-next-line no-sequences
587 ((errors) => (map.set(compilation, errors), errors))(
588 compilation.getErrors()
589 );
590 }
591 if (!context.cachedGetWarnings) {
592 /** @type {WeakMap<Compilation, Error[]>} */
593 const map = new WeakMap();
594 context.cachedGetWarnings = (compilation) =>
595 map.get(compilation) ||
596 // eslint-disable-next-line no-sequences
597 ((warnings) => (map.set(compilation, warnings), warnings))(
598 compilation.getWarnings()
599 );
600 }
601 if (compilation.name) {
602 object.name = compilation.name;
603 }
604 if (compilation.needAdditionalPass) {
605 object.needAdditionalPass = true;
606 }
607
608 const { logging, loggingDebug, loggingTrace } = options;
609 if (logging || (loggingDebug && loggingDebug.length > 0)) {
610 const util = require("util");
611
612 object.logging = {};
613 /** @type {Set<keyof LogType>} */
614 let acceptedTypes;
615 let collapsedGroups = false;
616 switch (logging) {
617 case "error":
618 acceptedTypes = new Set([LogType.error]);
619 break;
620 case "warn":
621 acceptedTypes = new Set([LogType.error, LogType.warn]);
622 break;
623 case "info":
624 acceptedTypes = new Set([
625 LogType.error,
626 LogType.warn,
627 LogType.info
628 ]);
629 break;
630 case "log":
631 acceptedTypes = new Set([
632 LogType.error,
633 LogType.warn,
634 LogType.info,
635 LogType.log,
636 LogType.group,
637 LogType.groupEnd,
638 LogType.groupCollapsed,
639 LogType.clear
640 ]);
641 break;
642 case "verbose":
643 acceptedTypes = new Set([
644 LogType.error,
645 LogType.warn,
646 LogType.info,
647 LogType.log,
648 LogType.group,
649 LogType.groupEnd,
650 LogType.groupCollapsed,
651 LogType.profile,
652 LogType.profileEnd,
653 LogType.time,
654 LogType.status,
655 LogType.clear
656 ]);
657 collapsedGroups = true;
658 break;
659 default:
660 acceptedTypes = new Set();
661 break;
662 }
663 const cachedMakePathsRelative = makePathsRelative.bindContextCache(
664 options.context,
665 compilation.compiler.root
666 );
667 let depthInCollapsedGroup = 0;
668 for (const [origin, logEntries] of compilation.logging) {
669 const debugMode = loggingDebug.some((fn) => fn(origin));
670 if (logging === false && !debugMode) continue;
671 /** @type {KnownStatsLoggingEntry[]} */
672 const groupStack = [];
673 /** @type {KnownStatsLoggingEntry[]} */
674 const rootList = [];
675 let currentList = rootList;
676 let processedLogEntries = 0;
677 for (const entry of logEntries) {
678 let type = entry.type;
679 if (!debugMode && !acceptedTypes.has(type)) continue;
680
681 // Expand groups in verbose and debug modes
682 if (
683 type === LogType.groupCollapsed &&
684 (debugMode || collapsedGroups)
685 ) {
686 type = LogType.group;
687 }
688
689 if (depthInCollapsedGroup === 0) {
690 processedLogEntries++;
691 }
692
693 if (type === LogType.groupEnd) {
694 groupStack.pop();
695 currentList =
696 groupStack.length > 0
697 ? /** @type {KnownStatsLoggingEntry[]} */ (
698 groupStack[groupStack.length - 1].children
699 )
700 : rootList;
701 if (depthInCollapsedGroup > 0) depthInCollapsedGroup--;
702 continue;
703 }
704 /** @type {undefined | string} */
705 let message;
706 if (entry.type === LogType.time) {
707 const [label, first, second] =
708 /** @type {[string, number, number]} */
709 (entry.args);
710 message = `${label}: ${first * 1000 + second / 1000000} ms`;
711 } else if (entry.args && entry.args.length > 0) {
712 message = util.format(entry.args[0], ...entry.args.slice(1));
713 }
714 /** @type {KnownStatsLoggingEntry} */
715 const newEntry = {
716 ...entry,
717 type,
718 message,
719 trace: loggingTrace ? entry.trace : undefined,
720 children:
721 type === LogType.group || type === LogType.groupCollapsed
722 ? []
723 : undefined
724 };
725 currentList.push(newEntry);
726 if (newEntry.children) {
727 groupStack.push(newEntry);
728 currentList = newEntry.children;
729 if (depthInCollapsedGroup > 0) {
730 depthInCollapsedGroup++;
731 } else if (type === LogType.groupCollapsed) {
732 depthInCollapsedGroup = 1;
733 }
734 }
735 }
736 let name = cachedMakePathsRelative(origin).replace(/\|/g, " ");
737 if (name in object.logging) {
738 let i = 1;
739 while (`${name}#${i}` in object.logging) {
740 i++;
741 }
742 name = `${name}#${i}`;
743 }
744 object.logging[name] = {
745 entries: rootList,
746 filteredEntries: logEntries.length - processedLogEntries,
747 debug: debugMode
748 };
749 }
750 }
751 },
752 hash: (object, compilation) => {
753 object.hash = compilation.hash;
754 },
755 version: (object) => {
756 object.version = require("../../package.json").version;
757 },
758 env: (object, compilation, context, { _env }) => {
759 object.env = _env;
760 },
761 timings: (object, compilation) => {
762 object.time =
763 /** @type {number} */ (compilation.endTime) -
764 /** @type {number} */ (compilation.startTime);
765 },
766 builtAt: (object, compilation) => {
767 object.builtAt = /** @type {number} */ (compilation.endTime);
768 },
769 publicPath: (object, compilation) => {
770 object.publicPath = compilation.getPath(
771 compilation.outputOptions.publicPath
772 );
773 },
774 outputPath: (object, compilation) => {
775 object.outputPath = compilation.outputOptions.path;
776 },
777 assets: (object, compilation, context, options, factory) => {
778 const { type } = context;
779 /** @type {Map<string, Chunk[]>} */
780 const compilationFileToChunks = new Map();
781 /** @type {Map<string, Chunk[]>} */
782 const compilationAuxiliaryFileToChunks = new Map();
783 for (const chunk of compilation.chunks) {
784 for (const file of chunk.files) {
785 let array = compilationFileToChunks.get(file);
786 if (array === undefined) {
787 array = [];
788 compilationFileToChunks.set(file, array);
789 }
790 array.push(chunk);
791 }
792 for (const file of chunk.auxiliaryFiles) {
793 let array = compilationAuxiliaryFileToChunks.get(file);
794 if (array === undefined) {
795 array = [];
796 compilationAuxiliaryFileToChunks.set(file, array);
797 }
798 array.push(chunk);
799 }
800 }
801 /** @type {Map<string, PreprocessedAsset>} */
802 const assetMap = new Map();
803 /** @type {Set<PreprocessedAsset>} */
804 const assets = new Set();
805 for (const asset of compilation.getAssets()) {
806 /** @type {PreprocessedAsset} */
807 const item = {
808 ...asset,
809 type: "asset",
810 related: undefined
811 };
812 assets.add(item);
813 assetMap.set(asset.name, item);
814 }
815 for (const item of assetMap.values()) {
816 const related = item.info.related;
817 if (!related) continue;
818 for (const type of Object.keys(related)) {
819 const relatedEntry = related[type];
820 const deps = Array.isArray(relatedEntry)
821 ? relatedEntry
822 : [relatedEntry];
823 for (const dep of deps) {
824 if (!dep) continue;
825 const depItem = assetMap.get(dep);
826 if (!depItem) continue;
827 assets.delete(depItem);
828 depItem.type = type;
829 item.related = item.related || [];
830 item.related.push(depItem);
831 }
832 }
833 }
834
835 object.assetsByChunkName = {};
836 for (const [file, chunks] of [
837 ...compilationFileToChunks,
838 ...compilationAuxiliaryFileToChunks
839 ]) {
840 for (const chunk of chunks) {
841 const name = chunk.name;
842 if (!name) continue;
843 if (
844 !Object.prototype.hasOwnProperty.call(
845 object.assetsByChunkName,
846 name
847 )
848 ) {
849 object.assetsByChunkName[name] = [];
850 }
851 object.assetsByChunkName[name].push(file);
852 }
853 }
854
855 const groupedAssets = factory.create(`${type}.assets`, [...assets], {
856 ...context,
857 compilationFileToChunks,
858 compilationAuxiliaryFileToChunks
859 });
860 const limited = spaceLimited(
861 groupedAssets,
862 /** @type {number} */ (options.assetsSpace)
863 );
864 object.assets = limited.children;
865 object.filteredAssets = limited.filteredChildren;
866 },
867 chunks: (object, compilation, context, options, factory) => {
868 const { type } = context;
869 object.chunks = factory.create(
870 `${type}.chunks`,
871 [...compilation.chunks],
872 context
873 );
874 },
875 modules: (object, compilation, context, options, factory) => {
876 const { type } = context;
877 const array = [...compilation.modules];
878 const groupedModules = factory.create(`${type}.modules`, array, context);
879 const limited = spaceLimited(groupedModules, options.modulesSpace);
880 object.modules = limited.children;
881 object.filteredModules = limited.filteredChildren;
882 },
883 entrypoints: (
884 object,
885 compilation,
886 context,
887 { entrypoints, chunkGroups, chunkGroupAuxiliary, chunkGroupChildren },
888 factory
889 ) => {
890 const { type } = context;
891 /** @type {ChunkGroupInfoWithName[]} */
892 const array = Array.from(compilation.entrypoints, ([key, value]) => ({
893 name: key,
894 chunkGroup: value
895 }));
896 if (entrypoints === "auto" && !chunkGroups) {
897 if (array.length > 5) return;
898 if (
899 !chunkGroupChildren &&
900 array.every(({ chunkGroup }) => {
901 if (chunkGroup.chunks.length !== 1) return false;
902 const chunk = chunkGroup.chunks[0];
903 return (
904 chunk.files.size === 1 &&
905 (!chunkGroupAuxiliary || chunk.auxiliaryFiles.size === 0)
906 );
907 })
908 ) {
909 return;
910 }
911 }
912 object.entrypoints = factory.create(
913 `${type}.entrypoints`,
914 array,
915 context
916 );
917 },
918 chunkGroups: (object, compilation, context, options, factory) => {
919 const { type } = context;
920 const array = Array.from(
921 compilation.namedChunkGroups,
922 ([key, value]) => ({
923 name: key,
924 chunkGroup: value
925 })
926 );
927 object.namedChunkGroups = factory.create(
928 `${type}.namedChunkGroups`,
929 array,
930 context
931 );
932 },
933 errors: (object, compilation, context, options, factory) => {
934 const { type, cachedGetErrors } = context;
935 const rawErrors = cachedGetErrors(compilation);
936 const factorizedErrors = factory.create(
937 `${type}.errors`,
938 cachedGetErrors(compilation),
939 context
940 );
941 let filtered = 0;
942 if (options.errorDetails === "auto" && rawErrors.length >= 3) {
943 filtered = rawErrors
944 .map(
945 (e) =>
946 typeof e !== "string" && /** @type {WebpackError} */ (e).details
947 )
948 .filter(Boolean).length;
949 }
950 if (
951 options.errorDetails === true ||
952 !Number.isFinite(options.errorsSpace)
953 ) {
954 object.errors = factorizedErrors;
955 if (filtered) object.filteredErrorDetailsCount = filtered;
956 return;
957 }
958 const [errors, filteredBySpace] = errorsSpaceLimit(
959 factorizedErrors,
960 /** @type {number} */
961 (options.errorsSpace)
962 );
963 object.filteredErrorDetailsCount = filtered + filteredBySpace;
964 object.errors = errors;
965 },
966 errorsCount: (object, compilation, { cachedGetErrors }) => {
967 object.errorsCount = countWithChildren(compilation, (c) =>
968 cachedGetErrors(c)
969 );
970 },
971 warnings: (object, compilation, context, options, factory) => {
972 const { type, cachedGetWarnings } = context;
973 const rawWarnings = factory.create(
974 `${type}.warnings`,
975 cachedGetWarnings(compilation),
976 context
977 );
978 let filtered = 0;
979 if (options.errorDetails === "auto") {
980 filtered = cachedGetWarnings(compilation)
981 .map(
982 (e) =>
983 typeof e !== "string" && /** @type {WebpackError} */ (e).details
984 )
985 .filter(Boolean).length;
986 }
987 if (
988 options.errorDetails === true ||
989 !Number.isFinite(options.warningsSpace)
990 ) {
991 object.warnings = rawWarnings;
992 if (filtered) object.filteredWarningDetailsCount = filtered;
993 return;
994 }
995 const [warnings, filteredBySpace] = errorsSpaceLimit(
996 rawWarnings,
997 /** @type {number} */
998 (options.warningsSpace)
999 );
1000 object.filteredWarningDetailsCount = filtered + filteredBySpace;
1001 object.warnings = warnings;
1002 },
1003 warningsCount: (
1004 object,
1005 compilation,
1006 context,
1007 { warningsFilter },
1008 factory
1009 ) => {
1010 const { type, cachedGetWarnings } = context;
1011 object.warningsCount = countWithChildren(compilation, (c, childType) => {
1012 if (
1013 !warningsFilter &&
1014 /** @type {KnownNormalizedStatsOptions["warningsFilter"]} */
1015 (warningsFilter).length === 0
1016 ) {
1017 // Type is wrong, because we don't need the real value for counting
1018 return /** @type {EXPECTED_ANY[]} */ (cachedGetWarnings(c));
1019 }
1020 return factory
1021 .create(`${type}${childType}.warnings`, cachedGetWarnings(c), context)
1022 .filter(
1023 /**
1024 * Handles the warnings count callback for this hook.
1025 * @param {StatsError} warning warning
1026 * @returns {boolean} result
1027 */
1028 (warning) => {
1029 const warningString = Object.keys(warning)
1030 .map(
1031 (key) =>
1032 `${warning[/** @type {keyof KnownStatsError} */ (key)]}`
1033 )
1034 .join("\n");
1035 return !warningsFilter.some((filter) =>
1036 filter(warning, warningString)
1037 );
1038 }
1039 );
1040 });
1041 },
1042 children: (object, compilation, context, options, factory) => {
1043 const { type } = context;
1044 object.children = factory.create(
1045 `${type}.children`,
1046 compilation.children,
1047 context
1048 );
1049 }
1050 },
1051 asset: {
1052 _: (object, asset, context, options, factory) => {
1053 const { compilation } = context;
1054 object.type = asset.type;
1055 object.name = asset.name;
1056 object.size = asset.source.size();
1057 object.emitted = compilation.emittedAssets.has(asset.name);
1058 object.comparedForEmit = compilation.comparedForEmitAssets.has(
1059 asset.name
1060 );
1061 const cached = !object.emitted && !object.comparedForEmit;
1062 object.cached = cached;
1063 object.info = asset.info;
1064 if (!cached || options.cachedAssets) {
1065 Object.assign(
1066 object,
1067 factory.create(`${context.type}$visible`, asset, context)
1068 );
1069 }
1070 }
1071 },
1072 asset$visible: {
1073 _: (
1074 object,
1075 asset,
1076 { compilationFileToChunks, compilationAuxiliaryFileToChunks }
1077 ) => {
1078 const chunks = compilationFileToChunks.get(asset.name) || [];
1079 const auxiliaryChunks =
1080 compilationAuxiliaryFileToChunks.get(asset.name) || [];
1081 object.chunkNames = uniqueOrderedArray(
1082 chunks,
1083 (c) => (c.name ? [c.name] : []),
1084 compareIds
1085 );
1086 object.chunkIdHints = uniqueOrderedArray(
1087 chunks,
1088 (c) => [...c.idNameHints],
1089 compareIds
1090 );
1091 object.auxiliaryChunkNames = uniqueOrderedArray(
1092 auxiliaryChunks,
1093 (c) => (c.name ? [c.name] : []),
1094 compareIds
1095 );
1096 object.auxiliaryChunkIdHints = uniqueOrderedArray(
1097 auxiliaryChunks,
1098 (c) => [...c.idNameHints],
1099 compareIds
1100 );
1101 object.filteredRelated = asset.related ? asset.related.length : undefined;
1102 },
1103 relatedAssets: (object, asset, context, options, factory) => {
1104 const { type } = context;
1105 object.related = factory.create(
1106 `${type.slice(0, -8)}.related`,
1107 asset.related || [],
1108 context
1109 );
1110 object.filteredRelated = asset.related
1111 ? asset.related.length -
1112 /** @type {StatsAsset[]} */ (object.related).length
1113 : undefined;
1114 },
1115 ids: (
1116 object,
1117 asset,
1118 { compilationFileToChunks, compilationAuxiliaryFileToChunks }
1119 ) => {
1120 const chunks = compilationFileToChunks.get(asset.name) || [];
1121 const auxiliaryChunks =
1122 compilationAuxiliaryFileToChunks.get(asset.name) || [];
1123 object.chunks = uniqueOrderedArray(
1124 chunks,
1125 (c) => /** @type {ChunkId[]} */ (c.ids),
1126 compareIds
1127 );
1128 object.auxiliaryChunks = uniqueOrderedArray(
1129 auxiliaryChunks,
1130 (c) => /** @type {ChunkId[]} */ (c.ids),
1131 compareIds
1132 );
1133 },
1134 performance: (object, asset) => {
1135 object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(asset.source);
1136 }
1137 },
1138 chunkGroup: {
1139 _: (
1140 object,
1141 { name, chunkGroup },
1142 { compilation, compilation: { moduleGraph, chunkGraph } },
1143 { ids, chunkGroupAuxiliary, chunkGroupChildren, chunkGroupMaxAssets }
1144 ) => {
1145 const children =
1146 chunkGroupChildren &&
1147 chunkGroup.getChildrenByOrders(moduleGraph, chunkGraph);
1148 /**
1149 * Returns } Asset object.
1150 * @param {string} name Name
1151 * @returns {{ name: string, size: number }} Asset object
1152 */
1153 const toAsset = (name) => {
1154 const asset = compilation.getAsset(name);
1155 return {
1156 name,
1157 size: /** @type {number} */ (asset ? asset.info.size : -1)
1158 };
1159 };
1160 /** @type {(total: number, asset: { size: number }) => number} */
1161 const sizeReducer = (total, { size }) => total + size;
1162 const assets = uniqueArray(chunkGroup.chunks, (c) => c.files).map(
1163 toAsset
1164 );
1165 const auxiliaryAssets = uniqueOrderedArray(
1166 chunkGroup.chunks,
1167 (c) => c.auxiliaryFiles,
1168 compareIds
1169 ).map(toAsset);
1170 const assetsSize = assets.reduce(sizeReducer, 0);
1171 const auxiliaryAssetsSize = auxiliaryAssets.reduce(sizeReducer, 0);
1172 /** @type {KnownStatsChunkGroup} */
1173 const statsChunkGroup = {
1174 name,
1175 chunks: ids
1176 ? /** @type {ChunkId[]} */ (chunkGroup.chunks.map((c) => c.id))
1177 : undefined,
1178 assets: assets.length <= chunkGroupMaxAssets ? assets : undefined,
1179 filteredAssets:
1180 assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
1181 assetsSize,
1182 auxiliaryAssets:
1183 chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
1184 ? auxiliaryAssets
1185 : undefined,
1186 filteredAuxiliaryAssets:
1187 chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
1188 ? 0
1189 : auxiliaryAssets.length,
1190 auxiliaryAssetsSize,
1191 children: children
1192 ? mapObject(children, (groups) =>
1193 groups.map((group) => {
1194 const assets = uniqueArray(group.chunks, (c) => c.files).map(
1195 toAsset
1196 );
1197 const auxiliaryAssets = uniqueOrderedArray(
1198 group.chunks,
1199 (c) => c.auxiliaryFiles,
1200 compareIds
1201 ).map(toAsset);
1202
1203 /** @type {KnownStatsChunkGroup} */
1204 const childStatsChunkGroup = {
1205 name: group.name,
1206 chunks: ids
1207 ? /** @type {ChunkId[]} */
1208 (group.chunks.map((c) => c.id))
1209 : undefined,
1210 assets:
1211 assets.length <= chunkGroupMaxAssets ? assets : undefined,
1212 filteredAssets:
1213 assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
1214 auxiliaryAssets:
1215 chunkGroupAuxiliary &&
1216 auxiliaryAssets.length <= chunkGroupMaxAssets
1217 ? auxiliaryAssets
1218 : undefined,
1219 filteredAuxiliaryAssets:
1220 chunkGroupAuxiliary &&
1221 auxiliaryAssets.length <= chunkGroupMaxAssets
1222 ? 0
1223 : auxiliaryAssets.length
1224 };
1225
1226 return childStatsChunkGroup;
1227 })
1228 )
1229 : undefined,
1230 childAssets: children
1231 ? mapObject(children, (groups) => {
1232 /** @type {Set<string>} */
1233 const set = new Set();
1234 for (const group of groups) {
1235 for (const chunk of group.chunks) {
1236 for (const asset of chunk.files) {
1237 set.add(asset);
1238 }
1239 }
1240 }
1241 return [...set];
1242 })
1243 : undefined
1244 };
1245 Object.assign(object, statsChunkGroup);
1246 },
1247 performance: (object, { chunkGroup }) => {
1248 object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(chunkGroup);
1249 }
1250 },
1251 module: {
1252 _: (object, module, context, options, factory) => {
1253 const { type } = context;
1254 const compilation = /** @type {Compilation} */ (context.compilation);
1255 const built = compilation.builtModules.has(module);
1256 const codeGenerated = compilation.codeGeneratedModules.has(module);
1257 const buildTimeExecuted =
1258 compilation.buildTimeExecutedModules.has(module);
1259 /** @type {{ [x: string]: number }} */
1260 const sizes = {};
1261 for (const sourceType of module.getSourceTypes()) {
1262 sizes[sourceType] = module.size(sourceType);
1263 }
1264 /** @type {KnownStatsModule} */
1265 const statsModule = {
1266 type: "module",
1267 moduleType: module.type,
1268 layer: module.layer,
1269 size: module.size(),
1270 sizes,
1271 built,
1272 codeGenerated,
1273 buildTimeExecuted,
1274 cached: !built && !codeGenerated
1275 };
1276 Object.assign(object, statsModule);
1277 if (built || codeGenerated || options.cachedModules) {
1278 Object.assign(
1279 object,
1280 factory.create(`${type}$visible`, module, context)
1281 );
1282 }
1283 }
1284 },
1285 module$visible: {
1286 _: (object, module, context, { requestShortener }, factory) => {
1287 const { type, rootModules } = context;
1288 const compilation = /** @type {Compilation} */ (context.compilation);
1289 const { moduleGraph } = compilation;
1290 /** @type {ModuleIssuerPath} */
1291 const path = [];
1292 const issuer = moduleGraph.getIssuer(module);
1293 let current = issuer;
1294 while (current) {
1295 path.push(current);
1296 current = moduleGraph.getIssuer(current);
1297 }
1298 path.reverse();
1299 const profile = moduleGraph.getProfile(module);
1300 const errors = module.getErrors();
1301 const errorsCount = errors !== undefined ? countIterable(errors) : 0;
1302 const warnings = module.getWarnings();
1303 const warningsCount =
1304 warnings !== undefined ? countIterable(warnings) : 0;
1305 /** @type {KnownStatsModule} */
1306 const statsModule = {
1307 identifier: module.identifier(),
1308 name: module.readableIdentifier(requestShortener),
1309 nameForCondition: module.nameForCondition(),
1310 index: /** @type {number} */ (moduleGraph.getPreOrderIndex(module)),
1311 preOrderIndex: /** @type {number} */ (
1312 moduleGraph.getPreOrderIndex(module)
1313 ),
1314 index2: /** @type {number} */ (moduleGraph.getPostOrderIndex(module)),
1315 postOrderIndex: /** @type {number} */ (
1316 moduleGraph.getPostOrderIndex(module)
1317 ),
1318 cacheable: /** @type {BuildInfo} */ (module.buildInfo).cacheable,
1319 optional: module.isOptional(moduleGraph),
1320 orphan:
1321 !type.endsWith("module.modules[].module$visible") &&
1322 compilation.chunkGraph.getNumberOfModuleChunks(module) === 0,
1323 dependent: rootModules ? !rootModules.has(module) : undefined,
1324 issuer: issuer && issuer.identifier(),
1325 issuerName: issuer && issuer.readableIdentifier(requestShortener),
1326 issuerPath:
1327 issuer &&
1328 /** @type {StatsModuleIssuer[] | undefined} */
1329 (factory.create(`${type.slice(0, -8)}.issuerPath`, path, context)),
1330 failed: errorsCount > 0,
1331 errors: errorsCount,
1332 warnings: warningsCount
1333 };
1334 Object.assign(object, statsModule);
1335 if (profile) {
1336 object.profile = factory.create(
1337 `${type.slice(0, -8)}.profile`,
1338 profile,
1339 context
1340 );
1341 }
1342 },
1343 ids: (object, module, { compilation: { chunkGraph, moduleGraph } }) => {
1344 object.id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
1345 const issuer = moduleGraph.getIssuer(module);
1346 object.issuerId = issuer && chunkGraph.getModuleId(issuer);
1347 object.chunks =
1348 /** @type {ChunkId[]} */
1349 (
1350 Array.from(
1351 chunkGraph.getOrderedModuleChunksIterable(
1352 module,
1353 compareChunksById
1354 ),
1355 (chunk) => chunk.id
1356 )
1357 );
1358 },
1359 moduleAssets: (object, module) => {
1360 object.assets = /** @type {BuildInfo} */ (module.buildInfo).assets
1361 ? Object.keys(/** @type {BuildInfo} */ (module.buildInfo).assets)
1362 : [];
1363 },
1364 reasons: (object, module, context, options, factory) => {
1365 const {
1366 type,
1367 compilation: { moduleGraph }
1368 } = context;
1369 const groupsReasons = factory.create(
1370 `${type.slice(0, -8)}.reasons`,
1371 [...moduleGraph.getIncomingConnections(module)],
1372 context
1373 );
1374 const limited = spaceLimited(
1375 groupsReasons,
1376 /** @type {number} */
1377 (options.reasonsSpace)
1378 );
1379 object.reasons = limited.children;
1380 object.filteredReasons = limited.filteredChildren;
1381 },
1382 usedExports: (
1383 object,
1384 module,
1385 { runtime, compilation: { moduleGraph } }
1386 ) => {
1387 const usedExports = moduleGraph.getUsedExports(module, runtime);
1388 if (usedExports === null) {
1389 object.usedExports = null;
1390 } else if (typeof usedExports === "boolean") {
1391 object.usedExports = usedExports;
1392 } else {
1393 object.usedExports = [...usedExports];
1394 }
1395 },
1396 providedExports: (object, module, { compilation: { moduleGraph } }) => {
1397 const providedExports = moduleGraph.getProvidedExports(module);
1398 object.providedExports = Array.isArray(providedExports)
1399 ? providedExports
1400 : null;
1401 },
1402 optimizationBailout: (
1403 object,
1404 module,
1405 { compilation: { moduleGraph } },
1406 { requestShortener }
1407 ) => {
1408 object.optimizationBailout = moduleGraph
1409 .getOptimizationBailout(module)
1410 .map((item) => {
1411 if (typeof item === "function") return item(requestShortener);
1412 return item;
1413 });
1414 },
1415 depth: (object, module, { compilation: { moduleGraph } }) => {
1416 object.depth = moduleGraph.getDepth(module);
1417 },
1418 nestedModules: (object, module, context, options, factory) => {
1419 const { type } = context;
1420 const innerModules = /** @type {Module & { modules?: Module[] }} */ (
1421 module
1422 ).modules;
1423 if (Array.isArray(innerModules)) {
1424 const groupedModules = factory.create(
1425 `${type.slice(0, -8)}.modules`,
1426 innerModules,
1427 context
1428 );
1429 const limited = spaceLimited(
1430 groupedModules,
1431 options.nestedModulesSpace
1432 );
1433 object.modules = limited.children;
1434 object.filteredModules = limited.filteredChildren;
1435 }
1436 },
1437 source: (object, module) => {
1438 const originalSource = module.originalSource();
1439 if (originalSource) {
1440 object.source = originalSource.source();
1441 }
1442 }
1443 },
1444 profile: {
1445 _: (object, profile) => {
1446 /** @type {KnownStatsProfile} */
1447 const statsProfile = {
1448 total:
1449 profile.factory +
1450 profile.restoring +
1451 profile.integration +
1452 profile.building +
1453 profile.storing,
1454 resolving: profile.factory,
1455 restoring: profile.restoring,
1456 building: profile.building,
1457 integration: profile.integration,
1458 storing: profile.storing,
1459 additionalResolving: profile.additionalFactories,
1460 additionalIntegration: profile.additionalIntegration,
1461 // TODO remove this in webpack 6
1462 factory: profile.factory,
1463 // TODO remove this in webpack 6
1464 dependencies: profile.additionalFactories
1465 };
1466 Object.assign(object, statsProfile);
1467 }
1468 },
1469 moduleIssuer: {
1470 _: (object, module, context, { requestShortener }, factory) => {
1471 const { type } = context;
1472 const compilation = /** @type {Compilation} */ (context.compilation);
1473 const { moduleGraph } = compilation;
1474 const profile = moduleGraph.getProfile(module);
1475 /** @type {Partial<KnownStatsModuleIssuer>} */
1476 const statsModuleIssuer = {
1477 identifier: module.identifier(),
1478 name: module.readableIdentifier(requestShortener)
1479 };
1480 Object.assign(object, statsModuleIssuer);
1481 if (profile) {
1482 object.profile = factory.create(`${type}.profile`, profile, context);
1483 }
1484 },
1485 ids: (object, module, { compilation: { chunkGraph } }) => {
1486 object.id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
1487 }
1488 },
1489 moduleReason: {
1490 _: (object, reason, { runtime }, { requestShortener }) => {
1491 const dep = reason.dependency;
1492 const moduleDep =
1493 dep && dep instanceof ModuleDependency ? dep : undefined;
1494 /** @type {KnownStatsModuleReason} */
1495 const statsModuleReason = {
1496 moduleIdentifier: reason.originModule
1497 ? reason.originModule.identifier()
1498 : null,
1499 module: reason.originModule
1500 ? reason.originModule.readableIdentifier(requestShortener)
1501 : null,
1502 moduleName: reason.originModule
1503 ? reason.originModule.readableIdentifier(requestShortener)
1504 : null,
1505 resolvedModuleIdentifier: reason.resolvedOriginModule
1506 ? reason.resolvedOriginModule.identifier()
1507 : null,
1508 resolvedModule: reason.resolvedOriginModule
1509 ? reason.resolvedOriginModule.readableIdentifier(requestShortener)
1510 : null,
1511 type: reason.dependency ? reason.dependency.type : null,
1512 active: reason.isActive(runtime),
1513 explanation: reason.explanation,
1514 userRequest: (moduleDep && moduleDep.userRequest) || null
1515 };
1516 Object.assign(object, statsModuleReason);
1517 if (reason.dependency) {
1518 const locInfo = formatLocation(reason.dependency.loc);
1519 if (locInfo) {
1520 object.loc = locInfo;
1521 }
1522 }
1523 },
1524 ids: (object, reason, { compilation: { chunkGraph } }) => {
1525 object.moduleId = reason.originModule
1526 ? chunkGraph.getModuleId(reason.originModule)
1527 : null;
1528 object.resolvedModuleId = reason.resolvedOriginModule
1529 ? chunkGraph.getModuleId(reason.resolvedOriginModule)
1530 : null;
1531 }
1532 },
1533 chunk: {
1534 _: (object, chunk, { makePathsRelative, compilation: { chunkGraph } }) => {
1535 const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph);
1536
1537 /** @type {KnownStatsChunk} */
1538 const statsChunk = {
1539 rendered: chunk.rendered,
1540 initial: chunk.canBeInitial(),
1541 entry: chunk.hasRuntime(),
1542 recorded: AggressiveSplittingPlugin.wasChunkRecorded(chunk),
1543 reason: chunk.chunkReason,
1544 size: chunkGraph.getChunkModulesSize(chunk),
1545 sizes: chunkGraph.getChunkModulesSizes(chunk),
1546 names: chunk.name ? [chunk.name] : [],
1547 idHints: [...chunk.idNameHints],
1548 runtime:
1549 chunk.runtime === undefined
1550 ? undefined
1551 : typeof chunk.runtime === "string"
1552 ? [makePathsRelative(chunk.runtime)]
1553 : Array.from(chunk.runtime.sort(), makePathsRelative),
1554 files: [...chunk.files],
1555 auxiliaryFiles: [...chunk.auxiliaryFiles].sort(compareIds),
1556 hash: /** @type {string} */ (chunk.renderedHash),
1557 childrenByOrder: childIdByOrder
1558 };
1559 Object.assign(object, statsChunk);
1560 },
1561 ids: (object, chunk) => {
1562 object.id = /** @type {ChunkId} */ (chunk.id);
1563 },
1564 chunkRelations: (object, chunk, _context) => {
1565 /** @typedef {Set<ChunkId>} ChunkRelations */
1566 /** @type {ChunkRelations} */
1567 const parents = new Set();
1568 /** @type {ChunkRelations} */
1569 const children = new Set();
1570 /** @type {ChunkRelations} */
1571 const siblings = new Set();
1572
1573 for (const chunkGroup of chunk.groupsIterable) {
1574 for (const parentGroup of chunkGroup.parentsIterable) {
1575 for (const chunk of parentGroup.chunks) {
1576 parents.add(/** @type {ChunkId} */ (chunk.id));
1577 }
1578 }
1579 for (const childGroup of chunkGroup.childrenIterable) {
1580 for (const chunk of childGroup.chunks) {
1581 children.add(/** @type {ChunkId} */ (chunk.id));
1582 }
1583 }
1584 for (const sibling of chunkGroup.chunks) {
1585 if (sibling !== chunk) {
1586 siblings.add(/** @type {ChunkId} */ (sibling.id));
1587 }
1588 }
1589 }
1590 object.siblings = [...siblings].sort(compareIds);
1591 object.parents = [...parents].sort(compareIds);
1592 object.children = [...children].sort(compareIds);
1593 },
1594 chunkModules: (object, chunk, context, options, factory) => {
1595 const {
1596 type,
1597 compilation: { chunkGraph }
1598 } = context;
1599 const array = chunkGraph.getChunkModules(chunk);
1600 const groupedModules = factory.create(`${type}.modules`, array, {
1601 ...context,
1602 runtime: chunk.runtime,
1603 rootModules: new Set(chunkGraph.getChunkRootModules(chunk))
1604 });
1605 const limited = spaceLimited(groupedModules, options.chunkModulesSpace);
1606 object.modules = limited.children;
1607 object.filteredModules = limited.filteredChildren;
1608 },
1609 chunkOrigins: (object, chunk, context, options, factory) => {
1610 const {
1611 type,
1612 compilation: { chunkGraph }
1613 } = context;
1614 /** @type {Set<string>} */
1615 const originsKeySet = new Set();
1616 /** @type {OriginRecord[]} */
1617 const origins = [];
1618 for (const g of chunk.groupsIterable) {
1619 origins.push(...g.origins);
1620 }
1621 const array = origins.filter((origin) => {
1622 const key = [
1623 origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
1624 formatLocation(origin.loc),
1625 origin.request
1626 ].join();
1627 if (originsKeySet.has(key)) return false;
1628 originsKeySet.add(key);
1629 return true;
1630 });
1631 object.origins = factory.create(`${type}.origins`, array, context);
1632 }
1633 },
1634 chunkOrigin: {
1635 _: (object, origin, context, { requestShortener }) => {
1636 /** @type {KnownStatsChunkOrigin} */
1637 const statsChunkOrigin = {
1638 module: origin.module ? origin.module.identifier() : "",
1639 moduleIdentifier: origin.module ? origin.module.identifier() : "",
1640 moduleName: origin.module
1641 ? origin.module.readableIdentifier(requestShortener)
1642 : "",
1643 loc: formatLocation(origin.loc),
1644 request: origin.request
1645 };
1646 Object.assign(object, statsChunkOrigin);
1647 },
1648 ids: (object, origin, { compilation: { chunkGraph } }) => {
1649 object.moduleId = origin.module
1650 ? /** @type {ModuleId} */ (chunkGraph.getModuleId(origin.module))
1651 : undefined;
1652 }
1653 },
1654 error: EXTRACT_ERROR,
1655 warning: EXTRACT_ERROR,
1656 cause: EXTRACT_ERROR,
1657 moduleTraceItem: {
1658 _: (object, { origin, module }, context, { requestShortener }, factory) => {
1659 const {
1660 type,
1661 compilation: { moduleGraph }
1662 } = context;
1663 object.originIdentifier = origin.identifier();
1664 object.originName = origin.readableIdentifier(requestShortener);
1665 object.moduleIdentifier = module.identifier();
1666 object.moduleName = module.readableIdentifier(requestShortener);
1667 const dependencies = [...moduleGraph.getIncomingConnections(module)]
1668 .filter((c) => c.resolvedOriginModule === origin && c.dependency)
1669 .map((c) => c.dependency);
1670 object.dependencies = factory.create(
1671 `${type}.dependencies`,
1672 /** @type {Dependency[]} */
1673 ([...new Set(dependencies)]),
1674 context
1675 );
1676 },
1677 ids: (object, { origin, module }, { compilation: { chunkGraph } }) => {
1678 object.originId =
1679 /** @type {ModuleId} */
1680 (chunkGraph.getModuleId(origin));
1681 object.moduleId =
1682 /** @type {ModuleId} */
1683 (chunkGraph.getModuleId(module));
1684 }
1685 },
1686 moduleTraceDependency: {
1687 _: (object, dependency) => {
1688 object.loc = formatLocation(dependency.loc);
1689 }
1690 }
1691};
1692
1693/** @type {Record<string, Record<string, (thing: ModuleGraphConnection, context: StatsFactoryContext, options: NormalizedStatsOptions, idx: number, i: number) => boolean | undefined>>} */
1694const FILTER = {
1695 "module.reasons": {
1696 "!orphanModules": (reason, { compilation: { chunkGraph } }) => {
1697 if (
1698 reason.originModule &&
1699 chunkGraph.getNumberOfModuleChunks(reason.originModule) === 0
1700 ) {
1701 return false;
1702 }
1703 }
1704 }
1705};
1706
1707/** @type {Record<string, Record<string, (thing: KnownStatsError, context: StatsFactoryContext, options: NormalizedStatsOptions, idx: number, i: number) => boolean | undefined>>} */
1708const FILTER_RESULTS = {
1709 "compilation.warnings": {
1710 warningsFilter: util.deprecate(
1711 (warning, context, { warningsFilter }) => {
1712 const warningString = Object.keys(warning)
1713 .map(
1714 (key) => `${warning[/** @type {keyof KnownStatsError} */ (key)]}`
1715 )
1716 .join("\n");
1717 return !warningsFilter.some((filter) => filter(warning, warningString));
1718 },
1719 "config.stats.warningsFilter is deprecated in favor of config.ignoreWarnings",
1720 "DEP_WEBPACK_STATS_WARNINGS_FILTER"
1721 )
1722 }
1723};
1724
1725/** @type {Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext) => void>} */
1726const MODULES_SORTER = {
1727 _: (comparators, { compilation: { moduleGraph } }) => {
1728 comparators.push(
1729 compareSelect((m) => moduleGraph.getDepth(m), compareNumbers),
1730 compareSelect((m) => moduleGraph.getPreOrderIndex(m), compareNumbers),
1731 compareSelect((m) => m.identifier(), compareIds)
1732 );
1733 }
1734};
1735
1736/**
1737 * @type {{
1738 * "compilation.chunks": Record<string, (comparators: Comparator<Chunk>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1739 * "compilation.modules": Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1740 * "chunk.rootModules": Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1741 * "chunk.modules": Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1742 * "module.modules": Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1743 * "module.reasons": Record<string, (comparators: Comparator<ModuleGraphConnection>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1744 * "chunk.origins": Record<string, (comparators: Comparator<OriginRecord>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>,
1745 * }}
1746 */
1747const SORTERS = {
1748 "compilation.chunks": {
1749 _: (comparators) => {
1750 comparators.push(compareSelect((c) => c.id, compareIds));
1751 }
1752 },
1753 "compilation.modules": MODULES_SORTER,
1754 "chunk.rootModules": MODULES_SORTER,
1755 "chunk.modules": MODULES_SORTER,
1756 "module.modules": MODULES_SORTER,
1757 "module.reasons": {
1758 _: (comparators, _context) => {
1759 comparators.push(
1760 compareSelect((x) => x.originModule, compareModulesByIdentifier)
1761 );
1762 comparators.push(
1763 compareSelect((x) => x.resolvedOriginModule, compareModulesByIdentifier)
1764 );
1765 comparators.push(
1766 compareSelect(
1767 (x) => x.dependency,
1768 concatComparators(
1769 compareSelect(
1770 /**
1771 * Handles the callback for this hook.
1772 * @param {Dependency} x dependency
1773 * @returns {DependencyLocation} location
1774 */
1775 (x) => x.loc,
1776 compareLocations
1777 ),
1778 compareSelect((x) => x.type, compareIds)
1779 )
1780 )
1781 );
1782 }
1783 },
1784 "chunk.origins": {
1785 _: (comparators, { compilation: { chunkGraph } }) => {
1786 comparators.push(
1787 compareSelect(
1788 (origin) =>
1789 origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
1790 compareIds
1791 ),
1792 compareSelect((origin) => formatLocation(origin.loc), compareIds),
1793 compareSelect((origin) => origin.request, compareIds)
1794 );
1795 }
1796 }
1797};
1798
1799/**
1800 * Defines the children type used by this module.
1801 * @template T
1802 * @typedef {T & { children?: Children<T>[] | undefined, filteredChildren?: number }} Children
1803 */
1804
1805/**
1806 * Returns item size.
1807 * @template T
1808 * @param {Children<T>} item item
1809 * @returns {number} item size
1810 */
1811const getItemSize = (item) =>
1812 // Each item takes 1 line
1813 // + the size of the children
1814 // + 1 extra line when it has children and filteredChildren
1815 !item.children
1816 ? 1
1817 : item.filteredChildren
1818 ? 2 + getTotalSize(item.children)
1819 : 1 + getTotalSize(item.children);
1820
1821/**
1822 * Returns total size.
1823 * @template T
1824 * @param {Children<T>[]} children children
1825 * @returns {number} total size
1826 */
1827const getTotalSize = (children) => {
1828 let size = 0;
1829 for (const child of children) {
1830 size += getItemSize(child);
1831 }
1832 return size;
1833};
1834
1835/**
1836 * Returns total items.
1837 * @template T
1838 * @param {Children<T>[]} children children
1839 * @returns {number} total items
1840 */
1841const getTotalItems = (children) => {
1842 let count = 0;
1843 for (const child of children) {
1844 if (!child.children && !child.filteredChildren) {
1845 count++;
1846 } else {
1847 if (child.children) count += getTotalItems(child.children);
1848 if (child.filteredChildren) count += child.filteredChildren;
1849 }
1850 }
1851 return count;
1852};
1853
1854/**
1855 * Returns collapsed children.
1856 * @template T
1857 * @param {Children<T>[]} children children
1858 * @returns {Children<T>[]} collapsed children
1859 */
1860const collapse = (children) => {
1861 // After collapse each child must take exactly one line
1862 /** @type {Children<T>[]} */
1863 const newChildren = [];
1864 for (const child of children) {
1865 if (child.children) {
1866 let filteredChildren = child.filteredChildren || 0;
1867 filteredChildren += getTotalItems(child.children);
1868 newChildren.push({
1869 ...child,
1870 children: undefined,
1871 filteredChildren
1872 });
1873 } else {
1874 newChildren.push(child);
1875 }
1876 }
1877 return newChildren;
1878};
1879
1880/**
1881 * Returns result.
1882 * @template T
1883 * @param {Children<T>[]} itemsAndGroups item and groups
1884 * @param {number} max max
1885 * @param {boolean=} filteredChildrenLineReserved filtered children line reserved
1886 * @returns {Children<T>} result
1887 */
1888const spaceLimited = (
1889 itemsAndGroups,
1890 max,
1891 filteredChildrenLineReserved = false
1892) => {
1893 if (max < 1) {
1894 return /** @type {Children<T>} */ ({
1895 children: undefined,
1896 filteredChildren: getTotalItems(itemsAndGroups)
1897 });
1898 }
1899 /** @type {Children<T>[] | undefined} */
1900 let children;
1901 /** @type {number | undefined} */
1902 let filteredChildren;
1903 // This are the groups, which take 1+ lines each
1904 /** @type {Children<T>[] | undefined} */
1905 const groups = [];
1906 // The sizes of the groups are stored in groupSizes
1907 /** @type {number[]} */
1908 const groupSizes = [];
1909 // This are the items, which take 1 line each
1910 /** @type {Children<T>[]} */
1911 const items = [];
1912 // The total of group sizes
1913 let groupsSize = 0;
1914
1915 for (const itemOrGroup of itemsAndGroups) {
1916 // is item
1917 if (!itemOrGroup.children && !itemOrGroup.filteredChildren) {
1918 items.push(itemOrGroup);
1919 } else {
1920 groups.push(itemOrGroup);
1921 const size = getItemSize(itemOrGroup);
1922 groupSizes.push(size);
1923 groupsSize += size;
1924 }
1925 }
1926
1927 if (groupsSize + items.length <= max) {
1928 // The total size in the current state fits into the max
1929 // keep all
1930 children = groups.length > 0 ? [...groups, ...items] : items;
1931 } else if (groups.length === 0) {
1932 // slice items to max
1933 // inner space marks that lines for filteredChildren already reserved
1934 const limit = max - (filteredChildrenLineReserved ? 0 : 1);
1935 filteredChildren = items.length - limit;
1936 items.length = limit;
1937 children = items;
1938 } else {
1939 // limit is the size when all groups are collapsed
1940 const limit =
1941 groups.length +
1942 (filteredChildrenLineReserved || items.length === 0 ? 0 : 1);
1943 if (limit < max) {
1944 // calculate how much we are over the size limit
1945 // this allows to approach the limit faster
1946 /** @type {number} */
1947 let oversize;
1948 // If each group would take 1 line the total would be below the maximum
1949 // collapse some groups, keep items
1950 while (
1951 (oversize =
1952 groupsSize +
1953 items.length +
1954 (filteredChildren && !filteredChildrenLineReserved ? 1 : 0) -
1955 max) > 0
1956 ) {
1957 // Find the maximum group and process only this one
1958 const maxGroupSize = Math.max(...groupSizes);
1959 if (maxGroupSize < items.length) {
1960 filteredChildren = items.length;
1961 items.length = 0;
1962 continue;
1963 }
1964 for (let i = 0; i < groups.length; i++) {
1965 if (groupSizes[i] === maxGroupSize) {
1966 const group = groups[i];
1967 // run this algorithm recursively and limit the size of the children to
1968 // current size - oversize / number of groups
1969 // So it should always end up being smaller
1970 const headerSize = group.filteredChildren ? 2 : 1;
1971 const limited = spaceLimited(
1972 /** @type {Children<T>[]} */ (group.children),
1973 maxGroupSize -
1974 // we should use ceil to always feet in max
1975 Math.ceil(oversize / groups.length) -
1976 // we substitute size of group head
1977 headerSize,
1978 headerSize === 2
1979 );
1980 groups[i] = {
1981 ...group,
1982 children: limited.children,
1983 filteredChildren: limited.filteredChildren
1984 ? (group.filteredChildren || 0) + limited.filteredChildren
1985 : group.filteredChildren
1986 };
1987 const newSize = getItemSize(groups[i]);
1988 groupsSize -= maxGroupSize - newSize;
1989 groupSizes[i] = newSize;
1990 break;
1991 }
1992 }
1993 }
1994 children = [...groups, ...items];
1995 } else if (limit === max) {
1996 // If we have only enough space to show one line per group and one line for the filtered items
1997 // collapse all groups and items
1998 children = collapse(groups);
1999 filteredChildren = items.length;
2000 } else {
2001 // If we have no space
2002 // collapse complete group
2003 filteredChildren = getTotalItems(itemsAndGroups);
2004 }
2005 }
2006
2007 return /** @type {Children<T>} */ ({ children, filteredChildren });
2008};
2009
2010/**
2011 * Errors space limit.
2012 * @param {StatsError[]} errors errors
2013 * @param {number} max max
2014 * @returns {[StatsError[], number]} error space limit
2015 */
2016const errorsSpaceLimit = (errors, max) => {
2017 let filtered = 0;
2018 // Can not fit into limit
2019 // print only messages
2020 if (errors.length + 1 >= max) {
2021 return [
2022 errors.map((error) => {
2023 if (typeof error === "string" || !error.details) return error;
2024 filtered++;
2025 return { ...error, details: "" };
2026 }),
2027 filtered
2028 ];
2029 }
2030 let fullLength = errors.length;
2031 let result = errors;
2032
2033 let i = 0;
2034 for (; i < errors.length; i++) {
2035 const error = errors[i];
2036 if (typeof error !== "string" && error.details) {
2037 const splitted = error.details.split("\n");
2038 const len = splitted.length;
2039 fullLength += len;
2040 if (fullLength > max) {
2041 result = i > 0 ? errors.slice(0, i) : [];
2042 const overLimit = fullLength - max + 1;
2043 const error = errors[i++];
2044 result.push({
2045 ...error,
2046 details:
2047 /** @type {string} */
2048 (error.details).split("\n").slice(0, -overLimit).join("\n"),
2049 filteredDetails: overLimit
2050 });
2051 filtered = errors.length - i;
2052 for (; i < errors.length; i++) {
2053 const error = errors[i];
2054 if (typeof error === "string" || !error.details) result.push(error);
2055 result.push({ ...error, details: "" });
2056 }
2057 break;
2058 } else if (fullLength === max) {
2059 result = errors.slice(0, ++i);
2060 filtered = errors.length - i;
2061 for (; i < errors.length; i++) {
2062 const error = errors[i];
2063 if (typeof error === "string" || !error.details) result.push(error);
2064 result.push({ ...error, details: "" });
2065 }
2066 break;
2067 }
2068 }
2069 }
2070
2071 return [result, filtered];
2072};
2073
2074/**
2075 * Returns } asset size.
2076 * @template {{ size: number }} T
2077 * @param {T[]} children children
2078 * @param {T[]} assets assets
2079 * @returns {{ size: number }} asset size
2080 */
2081const assetGroup = (children, assets) => {
2082 let size = 0;
2083 for (const asset of children) {
2084 size += asset.size;
2085 }
2086 return { size };
2087};
2088
2089/** @typedef {{ size: number, sizes: Record<string, number> }} ModuleGroupBySizeResult */
2090
2091/**
2092 * Returns size and sizes.
2093 * @template {ModuleGroupBySizeResult} T
2094 * @param {Children<T>[]} children children
2095 * @param {KnownStatsModule[]} modules modules
2096 * @returns {ModuleGroupBySizeResult} size and sizes
2097 */
2098const moduleGroup = (children, modules) => {
2099 let size = 0;
2100 /** @type {Record<string, number>} */
2101 const sizes = {};
2102 for (const module of children) {
2103 size += module.size;
2104 for (const key of Object.keys(module.sizes)) {
2105 sizes[key] = (sizes[key] || 0) + module.sizes[key];
2106 }
2107 }
2108 return {
2109 size,
2110 sizes
2111 };
2112};
2113
2114/**
2115 * Returns } reason group.
2116 * @template {{ active: boolean }} T
2117 * @param {Children<T>[]} children children
2118 * @param {KnownStatsModuleReason[]} reasons reasons
2119 * @returns {{ active: boolean }} reason group
2120 */
2121const reasonGroup = (children, reasons) => {
2122 let active = false;
2123 for (const reason of children) {
2124 active = active || reason.active;
2125 }
2126 return {
2127 active
2128 };
2129};
2130
2131const GROUP_EXTENSION_REGEXP = /(\.[^.]+?)(?:\?|(?: \+ \d+ modules?)?$)/;
2132const GROUP_PATH_REGEXP = /(.+)[/\\][^/\\]+?(?:\?|(?: \+ \d+ modules?)?$)/;
2133
2134/** @typedef {{ type: string }} BaseGroup */
2135
2136/**
2137 * Defines the base group with children type used by this module.
2138 * @template T
2139 * @typedef {BaseGroup & { children: T[], size: number }} BaseGroupWithChildren
2140 */
2141
2142/** @typedef {(name: string, asset: StatsAsset) => boolean} AssetFilterItemFn */
2143
2144/**
2145 * Describes the assets groupers shape.
2146 * @typedef {{
2147 * _: (groupConfigs: GroupConfig<KnownStatsAsset, BaseGroup & { filteredChildren: number, size: number } | BaseGroupWithChildren<KnownStatsAsset>>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2148 * groupAssetsByInfo: (groupConfigs: GroupConfig<KnownStatsAsset, BaseGroupWithChildren<KnownStatsAsset>>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2149 * groupAssetsByChunk: (groupConfigs: GroupConfig<KnownStatsAsset, BaseGroupWithChildren<KnownStatsAsset>>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2150 * excludeAssets: (groupConfigs: GroupConfig<KnownStatsAsset, BaseGroup & { filteredChildren: number, size: number }>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2151 * }} AssetsGroupers
2152 */
2153
2154/** @type {AssetsGroupers} */
2155const ASSETS_GROUPERS = {
2156 _: (groupConfigs, context, options) => {
2157 /**
2158 * Processes the provided name.
2159 * @param {keyof KnownStatsAsset} name name
2160 * @param {boolean=} exclude need exclude?
2161 */
2162 const groupByFlag = (name, exclude) => {
2163 groupConfigs.push({
2164 getKeys: (asset) => (asset[name] ? ["1"] : undefined),
2165 getOptions: () => ({
2166 groupChildren: !exclude,
2167 force: exclude
2168 }),
2169 createGroup: (key, children, assets) =>
2170 exclude
2171 ? {
2172 type: "assets by status",
2173 [name]: Boolean(key),
2174 filteredChildren: assets.length,
2175 ...assetGroup(children, assets)
2176 }
2177 : {
2178 type: "assets by status",
2179 [name]: Boolean(key),
2180 children,
2181 ...assetGroup(children, assets)
2182 }
2183 });
2184 };
2185 const {
2186 groupAssetsByEmitStatus,
2187 groupAssetsByPath,
2188 groupAssetsByExtension
2189 } = options;
2190 if (groupAssetsByEmitStatus) {
2191 groupByFlag("emitted");
2192 groupByFlag("comparedForEmit");
2193 groupByFlag("isOverSizeLimit");
2194 }
2195 if (groupAssetsByEmitStatus || !options.cachedAssets) {
2196 groupByFlag("cached", !options.cachedAssets);
2197 }
2198 if (groupAssetsByPath || groupAssetsByExtension) {
2199 groupConfigs.push({
2200 getKeys: (asset) => {
2201 const extensionMatch =
2202 groupAssetsByExtension && GROUP_EXTENSION_REGEXP.exec(asset.name);
2203 const extension = extensionMatch ? extensionMatch[1] : "";
2204 const pathMatch =
2205 groupAssetsByPath && GROUP_PATH_REGEXP.exec(asset.name);
2206 const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
2207 /** @type {string[]} */
2208 const keys = [];
2209 if (groupAssetsByPath) {
2210 keys.push(".");
2211 if (extension) {
2212 keys.push(
2213 path.length
2214 ? `${path.join("/")}/*${extension}`
2215 : `*${extension}`
2216 );
2217 }
2218 while (path.length > 0) {
2219 keys.push(`${path.join("/")}/`);
2220 path.pop();
2221 }
2222 } else if (extension) {
2223 keys.push(`*${extension}`);
2224 }
2225 return keys;
2226 },
2227 createGroup: (key, children, assets) => ({
2228 type: groupAssetsByPath ? "assets by path" : "assets by extension",
2229 name: key,
2230 children,
2231 ...assetGroup(children, assets)
2232 })
2233 });
2234 }
2235 },
2236 groupAssetsByInfo: (groupConfigs, _context, _options) => {
2237 /**
2238 * Group by asset info flag.
2239 * @param {string} name name
2240 */
2241 const groupByAssetInfoFlag = (name) => {
2242 groupConfigs.push({
2243 getKeys: (asset) =>
2244 asset.info && asset.info[name] ? ["1"] : undefined,
2245 createGroup: (key, children, assets) => ({
2246 type: "assets by info",
2247 info: {
2248 [name]: Boolean(key)
2249 },
2250 children,
2251 ...assetGroup(children, assets)
2252 })
2253 });
2254 };
2255 groupByAssetInfoFlag("immutable");
2256 groupByAssetInfoFlag("development");
2257 groupByAssetInfoFlag("hotModuleReplacement");
2258 },
2259 groupAssetsByChunk: (groupConfigs, _context, _options) => {
2260 /**
2261 * Processes the provided name.
2262 * @param {keyof KnownStatsAsset} name name
2263 */
2264 const groupByNames = (name) => {
2265 groupConfigs.push({
2266 getKeys: (asset) => /** @type {string[]} */ (asset[name]),
2267 createGroup: (key, children, assets) => ({
2268 type: "assets by chunk",
2269 [name]: [key],
2270 children,
2271 ...assetGroup(children, assets)
2272 })
2273 });
2274 };
2275 groupByNames("chunkNames");
2276 groupByNames("auxiliaryChunkNames");
2277 groupByNames("chunkIdHints");
2278 groupByNames("auxiliaryChunkIdHints");
2279 },
2280 excludeAssets: (groupConfigs, context, { excludeAssets }) => {
2281 groupConfigs.push({
2282 getKeys: (asset) => {
2283 const ident = asset.name;
2284 const excluded = excludeAssets.some((fn) => fn(ident, asset));
2285 if (excluded) return ["excluded"];
2286 },
2287 getOptions: () => ({
2288 groupChildren: false,
2289 force: true
2290 }),
2291 createGroup: (key, children, assets) => ({
2292 type: "hidden assets",
2293 filteredChildren: assets.length,
2294 ...assetGroup(children, assets)
2295 })
2296 });
2297 }
2298};
2299
2300/**
2301 * Describes the modules groupers shape.
2302 * @typedef {{
2303 * _: (groupConfigs: GroupConfig<KnownStatsModule, BaseGroup & { filteredChildren?: number, children?: KnownStatsModule[], size: number, sizes: Record<string, number> }>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2304 * excludeModules: (groupConfigs: GroupConfig<KnownStatsModule, BaseGroup & { filteredChildren: number, size: number, sizes: Record<string, number> }>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2305 * }} ModulesGroupers
2306 */
2307
2308/** @typedef {(name: string, module: StatsModule, type: "module" | "chunk" | "root-of-chunk" | "nested") => boolean} ModuleFilterItemTypeFn */
2309
2310/**
2311 * @type {(type: ExcludeModulesType) => ModulesGroupers}
2312 */
2313const MODULES_GROUPERS = (type) => ({
2314 _: (groupConfigs, context, options) => {
2315 /**
2316 * Processes the provided name.
2317 * @param {keyof KnownStatsModule} name name
2318 * @param {string} type type
2319 * @param {boolean=} exclude need exclude?
2320 */
2321 const groupByFlag = (name, type, exclude) => {
2322 groupConfigs.push({
2323 getKeys: (module) => (module[name] ? ["1"] : undefined),
2324 getOptions: () => ({
2325 groupChildren: !exclude,
2326 force: exclude
2327 }),
2328 createGroup: (key, children, modules) => ({
2329 type,
2330 [name]: Boolean(key),
2331 ...(exclude ? { filteredChildren: modules.length } : { children }),
2332 ...moduleGroup(
2333 /** @type {(KnownStatsModule & ModuleGroupBySizeResult)[]} */
2334 (children),
2335 modules
2336 )
2337 })
2338 });
2339 };
2340 const {
2341 groupModulesByCacheStatus,
2342 groupModulesByLayer,
2343 groupModulesByAttributes,
2344 groupModulesByType,
2345 groupModulesByPath,
2346 groupModulesByExtension
2347 } = options;
2348 if (groupModulesByAttributes) {
2349 groupByFlag("errors", "modules with errors");
2350 groupByFlag("warnings", "modules with warnings");
2351 groupByFlag("assets", "modules with assets");
2352 groupByFlag("optional", "optional modules");
2353 }
2354 if (groupModulesByCacheStatus) {
2355 groupByFlag("cacheable", "cacheable modules");
2356 groupByFlag("built", "built modules");
2357 groupByFlag("codeGenerated", "code generated modules");
2358 }
2359 if (groupModulesByCacheStatus || !options.cachedModules) {
2360 groupByFlag("cached", "cached modules", !options.cachedModules);
2361 }
2362 if (groupModulesByAttributes || !options.orphanModules) {
2363 groupByFlag("orphan", "orphan modules", !options.orphanModules);
2364 }
2365 if (groupModulesByAttributes || !options.dependentModules) {
2366 groupByFlag("dependent", "dependent modules", !options.dependentModules);
2367 }
2368 if (groupModulesByType || !options.runtimeModules) {
2369 groupConfigs.push({
2370 getKeys: (module) => {
2371 if (!module.moduleType) return;
2372 if (groupModulesByType) {
2373 return [module.moduleType.split("/", 1)[0]];
2374 } else if (module.moduleType === WEBPACK_MODULE_TYPE_RUNTIME) {
2375 return [WEBPACK_MODULE_TYPE_RUNTIME];
2376 }
2377 },
2378 getOptions: (key) => {
2379 const exclude =
2380 key === WEBPACK_MODULE_TYPE_RUNTIME && !options.runtimeModules;
2381 return {
2382 groupChildren: !exclude,
2383 force: exclude
2384 };
2385 },
2386 createGroup: (key, children, modules) => {
2387 const exclude =
2388 key === WEBPACK_MODULE_TYPE_RUNTIME && !options.runtimeModules;
2389 return {
2390 type: `${key} modules`,
2391 moduleType: key,
2392 ...(exclude ? { filteredChildren: modules.length } : { children }),
2393 ...moduleGroup(
2394 /** @type {(KnownStatsModule & ModuleGroupBySizeResult)[]} */
2395 (children),
2396 modules
2397 )
2398 };
2399 }
2400 });
2401 }
2402 if (groupModulesByLayer) {
2403 groupConfigs.push({
2404 getKeys: (module) => /** @type {string[]} */ ([module.layer]),
2405 createGroup: (key, children, modules) => ({
2406 type: "modules by layer",
2407 layer: key,
2408 children,
2409 ...moduleGroup(
2410 /** @type {(KnownStatsModule & ModuleGroupBySizeResult)[]} */
2411 (children),
2412 modules
2413 )
2414 })
2415 });
2416 }
2417 if (groupModulesByPath || groupModulesByExtension) {
2418 groupConfigs.push({
2419 getKeys: (module) => {
2420 if (!module.name) return;
2421 const resource = parseResource(
2422 /** @type {string} */ (module.name.split("!").pop())
2423 ).path;
2424 const dataUrl = /^data:[^,;]+/.exec(resource);
2425 if (dataUrl) return [dataUrl[0]];
2426 const extensionMatch =
2427 groupModulesByExtension && GROUP_EXTENSION_REGEXP.exec(resource);
2428 const extension = extensionMatch ? extensionMatch[1] : "";
2429 const pathMatch =
2430 groupModulesByPath && GROUP_PATH_REGEXP.exec(resource);
2431 const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
2432 /** @type {string[]} */
2433 const keys = [];
2434 if (groupModulesByPath) {
2435 if (extension) {
2436 keys.push(
2437 path.length
2438 ? `${path.join("/")}/*${extension}`
2439 : `*${extension}`
2440 );
2441 }
2442 while (path.length > 0) {
2443 keys.push(`${path.join("/")}/`);
2444 path.pop();
2445 }
2446 } else if (extension) {
2447 keys.push(`*${extension}`);
2448 }
2449 return keys;
2450 },
2451 createGroup: (key, children, modules) => {
2452 const isDataUrl = key.startsWith("data:");
2453 return {
2454 type: isDataUrl
2455 ? "modules by mime type"
2456 : groupModulesByPath
2457 ? "modules by path"
2458 : "modules by extension",
2459 name: isDataUrl ? key.slice(/* 'data:'.length */ 5) : key,
2460 children,
2461 ...moduleGroup(
2462 /** @type {(KnownStatsModule & ModuleGroupBySizeResult)[]} */
2463 (children),
2464 modules
2465 )
2466 };
2467 }
2468 });
2469 }
2470 },
2471 excludeModules: (groupConfigs, context, { excludeModules }) => {
2472 groupConfigs.push({
2473 getKeys: (module) => {
2474 const name = module.name;
2475 if (name) {
2476 const excluded = excludeModules.some((fn) => fn(name, module, type));
2477 if (excluded) return ["1"];
2478 }
2479 },
2480 getOptions: () => ({
2481 groupChildren: false,
2482 force: true
2483 }),
2484 createGroup: (key, children, modules) => ({
2485 type: "hidden modules",
2486 filteredChildren: children.length,
2487 ...moduleGroup(
2488 /** @type {(KnownStatsModule & ModuleGroupBySizeResult)[]} */
2489 (children),
2490 modules
2491 )
2492 })
2493 });
2494 }
2495});
2496
2497/**
2498 * Defines the module reasons groupers type used by this module.
2499 * @typedef {{ groupReasonsByOrigin: (groupConfigs: GroupConfig<KnownStatsModuleReason, BaseGroup & { module: string, children: KnownStatsModuleReason[], active: boolean }>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void }} ModuleReasonsGroupers
2500 */
2501
2502/** @type {ModuleReasonsGroupers} */
2503const MODULE_REASONS_GROUPERS = {
2504 groupReasonsByOrigin: (groupConfigs) => {
2505 groupConfigs.push({
2506 getKeys: (reason) => /** @type {string[]} */ ([reason.module]),
2507 createGroup: (key, children, reasons) => ({
2508 type: "from origin",
2509 module: key,
2510 children,
2511 ...reasonGroup(children, reasons)
2512 })
2513 });
2514 }
2515};
2516
2517/**
2518 * @type {{
2519 * "compilation.assets": AssetsGroupers,
2520 * "asset.related": AssetsGroupers,
2521 * "compilation.modules": ModulesGroupers,
2522 * "chunk.modules": ModulesGroupers,
2523 * "chunk.rootModules": ModulesGroupers,
2524 * "module.modules": ModulesGroupers,
2525 * "module.reasons": ModuleReasonsGroupers,
2526 * }}
2527 */
2528const RESULT_GROUPERS = {
2529 "compilation.assets": ASSETS_GROUPERS,
2530 "asset.related": ASSETS_GROUPERS,
2531 "compilation.modules": MODULES_GROUPERS("module"),
2532 "chunk.modules": MODULES_GROUPERS("chunk"),
2533 "chunk.rootModules": MODULES_GROUPERS("root-of-chunk"),
2534 "module.modules": MODULES_GROUPERS("nested"),
2535 "module.reasons": MODULE_REASONS_GROUPERS
2536};
2537
2538// remove a prefixed "!" that can be specified to reverse sort order
2539/**
2540 * Normalizes field key.
2541 * @param {string} field a field name
2542 * @returns {field} normalized field
2543 */
2544const normalizeFieldKey = (field) => {
2545 if (field[0] === "!") {
2546 return field.slice(1);
2547 }
2548 return field;
2549};
2550
2551// if a field is prefixed by a "!" reverse sort order
2552/**
2553 * Sorts order regular.
2554 * @param {string} field a field name
2555 * @returns {boolean} result
2556 */
2557const sortOrderRegular = (field) => {
2558 if (field[0] === "!") {
2559 return false;
2560 }
2561 return true;
2562};
2563
2564/**
2565 * Returns comparators.
2566 * @template T
2567 * @param {string | false} field field name
2568 * @returns {(a: T, b: T) => 0 | 1 | -1} comparators
2569 */
2570const sortByField = (field) => {
2571 if (!field) {
2572 /**
2573 * Returns zero.
2574 * @param {T} a first
2575 * @param {T} b second
2576 * @returns {-1 | 0 | 1} zero
2577 */
2578 const noSort = (a, b) => 0;
2579 return noSort;
2580 }
2581
2582 const fieldKey = normalizeFieldKey(field);
2583
2584 let sortFn = compareSelect((m) => m[fieldKey], compareIds);
2585
2586 // if a field is prefixed with a "!" the sort is reversed!
2587 const sortIsRegular = sortOrderRegular(field);
2588
2589 if (!sortIsRegular) {
2590 const oldSortFn = sortFn;
2591 sortFn = (a, b) => oldSortFn(b, a);
2592 }
2593
2594 return sortFn;
2595};
2596
2597/**
2598 * Describes the asset sorters shape.
2599 * @typedef {{
2600 * assetsSort: (comparators: Comparator<Asset>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2601 * _: (comparators: Comparator<Asset>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void,
2602 * }} AssetSorters
2603 */
2604
2605/** @type {AssetSorters} */
2606const ASSET_SORTERS = {
2607 assetsSort: (comparators, context, { assetsSort }) => {
2608 comparators.push(sortByField(assetsSort));
2609 },
2610 _: (comparators) => {
2611 comparators.push(compareSelect((a) => a.name, compareIds));
2612 }
2613};
2614
2615/**
2616 * @type {{
2617 * "compilation.chunks": { chunksSort: (comparators: Comparator<Chunk>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void },
2618 * "compilation.modules": { modulesSort: (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void },
2619 * "chunk.modules": { chunkModulesSort: (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void },
2620 * "module.modules": { nestedModulesSort: (comparators: Comparator<Module>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void },
2621 * "compilation.assets": AssetSorters,
2622 * "asset.related": AssetSorters,
2623 * }}
2624 */
2625const RESULT_SORTERS = {
2626 "compilation.chunks": {
2627 chunksSort: (comparators, context, { chunksSort }) => {
2628 comparators.push(sortByField(chunksSort));
2629 }
2630 },
2631 "compilation.modules": {
2632 modulesSort: (comparators, context, { modulesSort }) => {
2633 comparators.push(sortByField(modulesSort));
2634 }
2635 },
2636 "chunk.modules": {
2637 chunkModulesSort: (comparators, context, { chunkModulesSort }) => {
2638 comparators.push(sortByField(chunkModulesSort));
2639 }
2640 },
2641 "module.modules": {
2642 nestedModulesSort: (comparators, context, { nestedModulesSort }) => {
2643 comparators.push(sortByField(nestedModulesSort));
2644 }
2645 },
2646 "compilation.assets": ASSET_SORTERS,
2647 "asset.related": ASSET_SORTERS
2648};
2649
2650/**
2651 * Defines the extract function type used by this module.
2652 * @template T
2653 * @typedef {T extends Record<string, Record<string, infer F>> ? F : never} ExtractFunction
2654 */
2655
2656/**
2657 * Processes the provided config.
2658 * @template {Record<string, Record<string, EXPECTED_ANY>>} T
2659 * @param {T} config the config see above
2660 * @param {NormalizedStatsOptions} options stats options
2661 * @param {(hookFor: keyof T, fn: ExtractFunction<T>) => void} fn handler function called for every active line in config
2662 * @returns {void}
2663 */
2664const iterateConfig = (config, options, fn) => {
2665 for (const hookFor of Object.keys(config)) {
2666 const subConfig = config[hookFor];
2667 for (const option of Object.keys(subConfig)) {
2668 if (option !== "_") {
2669 if (option.startsWith("!")) {
2670 if (options[option.slice(1)]) continue;
2671 } else {
2672 const value = options[option];
2673 if (
2674 value === false ||
2675 value === undefined ||
2676 (Array.isArray(value) && value.length === 0)
2677 ) {
2678 continue;
2679 }
2680 }
2681 }
2682 fn(hookFor, subConfig[option]);
2683 }
2684 }
2685};
2686
2687/** @type {Record<string, string>} */
2688const ITEM_NAMES = {
2689 "compilation.children[]": "compilation",
2690 "compilation.modules[]": "module",
2691 "compilation.entrypoints[]": "chunkGroup",
2692 "compilation.namedChunkGroups[]": "chunkGroup",
2693 "compilation.errors[]": "error",
2694 "compilation.warnings[]": "warning",
2695 "error.errors[]": "error",
2696 "warning.errors[]": "error",
2697 "chunk.modules[]": "module",
2698 "chunk.rootModules[]": "module",
2699 "chunk.origins[]": "chunkOrigin",
2700 "compilation.chunks[]": "chunk",
2701 "compilation.assets[]": "asset",
2702 "asset.related[]": "asset",
2703 "module.issuerPath[]": "moduleIssuer",
2704 "module.reasons[]": "moduleReason",
2705 "module.modules[]": "module",
2706 "module.children[]": "module",
2707 "moduleTrace[]": "moduleTraceItem",
2708 "moduleTraceItem.dependencies[]": "moduleTraceDependency"
2709};
2710
2711/**
2712 * Defines the named object type used by this module.
2713 * @template T
2714 * @typedef {{ name: T }} NamedObject
2715 */
2716
2717/**
2718 * Merges the provided values into a single result.
2719 * @template {{ name: string }} T
2720 * @param {T[]} items items to be merged
2721 * @returns {NamedObject<T>} an object
2722 */
2723const mergeToObject = (items) => {
2724 const obj = Object.create(null);
2725 for (const item of items) {
2726 obj[item.name] = item;
2727 }
2728 return obj;
2729};
2730
2731/**
2732 * @template {{ name: string }} T
2733 * @type {Record<string, (items: T[]) => NamedObject<T>>}
2734 */
2735const MERGER = {
2736 "compilation.entrypoints": mergeToObject,
2737 "compilation.namedChunkGroups": mergeToObject
2738};
2739
2740const PLUGIN_NAME = "DefaultStatsFactoryPlugin";
2741
2742class DefaultStatsFactoryPlugin {
2743 /**
2744 * Applies the plugin by registering its hooks on the compiler.
2745 * @param {Compiler} compiler the compiler instance
2746 * @returns {void}
2747 */
2748 apply(compiler) {
2749 compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
2750 compilation.hooks.statsFactory.tap(
2751 PLUGIN_NAME,
2752 /**
2753 * Handles the callback logic for this hook.
2754 * @param {StatsFactory} stats stats factory
2755 * @param {NormalizedStatsOptions} options stats options
2756 */
2757 (stats, options) => {
2758 iterateConfig(SIMPLE_EXTRACTORS, options, (hookFor, fn) => {
2759 stats.hooks.extract
2760 .for(hookFor)
2761 .tap(PLUGIN_NAME, (obj, data, ctx) =>
2762 fn(obj, data, ctx, options, stats)
2763 );
2764 });
2765 iterateConfig(FILTER, options, (hookFor, fn) => {
2766 stats.hooks.filter
2767 .for(hookFor)
2768 .tap(PLUGIN_NAME, (item, ctx, idx, i) =>
2769 fn(item, ctx, options, idx, i)
2770 );
2771 });
2772 iterateConfig(FILTER_RESULTS, options, (hookFor, fn) => {
2773 stats.hooks.filterResults
2774 .for(hookFor)
2775 .tap(PLUGIN_NAME, (item, ctx, idx, i) =>
2776 fn(item, ctx, options, idx, i)
2777 );
2778 });
2779 iterateConfig(SORTERS, options, (hookFor, fn) => {
2780 stats.hooks.sort
2781 .for(hookFor)
2782 .tap(PLUGIN_NAME, (comparators, ctx) =>
2783 fn(comparators, ctx, options)
2784 );
2785 });
2786 iterateConfig(RESULT_SORTERS, options, (hookFor, fn) => {
2787 stats.hooks.sortResults
2788 .for(hookFor)
2789 .tap(PLUGIN_NAME, (comparators, ctx) =>
2790 fn(comparators, ctx, options)
2791 );
2792 });
2793 iterateConfig(RESULT_GROUPERS, options, (hookFor, fn) => {
2794 stats.hooks.groupResults
2795 .for(hookFor)
2796 .tap(PLUGIN_NAME, (groupConfigs, ctx) =>
2797 fn(groupConfigs, ctx, options)
2798 );
2799 });
2800 for (const key of Object.keys(ITEM_NAMES)) {
2801 const itemName = ITEM_NAMES[key];
2802 stats.hooks.getItemName.for(key).tap(PLUGIN_NAME, () => itemName);
2803 }
2804 for (const key of Object.keys(MERGER)) {
2805 const merger = MERGER[key];
2806 stats.hooks.merge.for(key).tap(PLUGIN_NAME, merger);
2807 }
2808 if (options.children) {
2809 if (Array.isArray(options.children)) {
2810 stats.hooks.getItemFactory
2811 .for("compilation.children[].compilation")
2812 .tap(
2813 PLUGIN_NAME,
2814 /**
2815 * Handles the callback logic for this hook.
2816 * @param {Compilation} comp compilation
2817 * @param {StatsFactoryContext} options options
2818 * @returns {StatsFactory | undefined} stats factory
2819 */
2820 (comp, { _index: idx }) => {
2821 const children =
2822 /** @type {StatsValue[]} */
2823 (options.children);
2824 if (idx < children.length) {
2825 return compilation.createStatsFactory(
2826 compilation.createStatsOptions(children[idx])
2827 );
2828 }
2829 }
2830 );
2831 } else if (options.children !== true) {
2832 const childFactory = compilation.createStatsFactory(
2833 compilation.createStatsOptions(options.children)
2834 );
2835 stats.hooks.getItemFactory
2836 .for("compilation.children[].compilation")
2837 .tap(PLUGIN_NAME, () => childFactory);
2838 }
2839 }
2840 }
2841 );
2842 });
2843 }
2844}
2845
2846module.exports = DefaultStatsFactoryPlugin;
Note: See TracBrowser for help on using the repository browser.