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

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

F4 Finalna Verzija

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