Projekt

Obecné

Profil

Stáhnout (44.5 KB) Statistiky
| Větev: | Revize:
1
/*
2
	MIT License http://www.opensource.org/licenses/mit-license.php
3
	Author Tobias Koppers @sokra
4
*/
5
"use strict";
6

    
7
const RequestShortener = require("./RequestShortener");
8
const SizeFormatHelpers = require("./SizeFormatHelpers");
9
const formatLocation = require("./formatLocation");
10
const identifierUtils = require("./util/identifier");
11
const compareLocations = require("./compareLocations");
12
const { LogType } = require("./logging/Logger");
13

    
14
const optionsOrFallback = (...args) => {
15
	let optionValues = [];
16
	optionValues.push(...args);
17
	return optionValues.find(optionValue => optionValue !== undefined);
18
};
19

    
20
const compareId = (a, b) => {
21
	if (typeof a !== typeof b) {
22
		return typeof a < typeof b ? -1 : 1;
23
	}
24
	if (a < b) return -1;
25
	if (a > b) return 1;
26
	return 0;
27
};
28

    
29
class Stats {
30
	constructor(compilation) {
31
		this.compilation = compilation;
32
		this.hash = compilation.hash;
33
		this.startTime = undefined;
34
		this.endTime = undefined;
35
	}
36

    
37
	static filterWarnings(warnings, warningsFilter) {
38
		// we dont have anything to filter so all warnings can be shown
39
		if (!warningsFilter) {
40
			return warnings;
41
		}
42

    
43
		// create a chain of filters
44
		// if they return "true" a warning should be suppressed
45
		const normalizedWarningsFilters = [].concat(warningsFilter).map(filter => {
46
			if (typeof filter === "string") {
47
				return warning => warning.includes(filter);
48
			}
49

    
50
			if (filter instanceof RegExp) {
51
				return warning => filter.test(warning);
52
			}
53

    
54
			if (typeof filter === "function") {
55
				return filter;
56
			}
57

    
58
			throw new Error(
59
				`Can only filter warnings with Strings or RegExps. (Given: ${filter})`
60
			);
61
		});
62
		return warnings.filter(warning => {
63
			return !normalizedWarningsFilters.some(check => check(warning));
64
		});
65
	}
66

    
67
	formatFilePath(filePath) {
68
		const OPTIONS_REGEXP = /^(\s|\S)*!/;
69
		return filePath.includes("!")
70
			? `${filePath.replace(OPTIONS_REGEXP, "")} (${filePath})`
71
			: `${filePath}`;
72
	}
73

    
74
	hasWarnings() {
75
		return (
76
			this.compilation.warnings.length > 0 ||
77
			this.compilation.children.some(child => child.getStats().hasWarnings())
78
		);
79
	}
80

    
81
	hasErrors() {
82
		return (
83
			this.compilation.errors.length > 0 ||
84
			this.compilation.children.some(child => child.getStats().hasErrors())
85
		);
86
	}
87

    
88
	// remove a prefixed "!" that can be specified to reverse sort order
89
	normalizeFieldKey(field) {
90
		if (field[0] === "!") {
91
			return field.substr(1);
92
		}
93
		return field;
94
	}
95

    
96
	// if a field is prefixed by a "!" reverse sort order
97
	sortOrderRegular(field) {
98
		if (field[0] === "!") {
99
			return false;
100
		}
101
		return true;
102
	}
103

    
104
	toJson(options, forToString) {
105
		if (typeof options === "boolean" || typeof options === "string") {
106
			options = Stats.presetToOptions(options);
107
		} else if (!options) {
108
			options = {};
109
		}
110

    
111
		const optionOrLocalFallback = (v, def) =>
112
			v !== undefined ? v : options.all !== undefined ? options.all : def;
113

    
114
		const testAgainstGivenOption = item => {
115
			if (typeof item === "string") {
116
				const regExp = new RegExp(
117
					`[\\\\/]${item.replace(
118
						// eslint-disable-next-line no-useless-escape
119
						/[-[\]{}()*+?.\\^$|]/g,
120
						"\\$&"
121
					)}([\\\\/]|$|!|\\?)`
122
				);
123
				return ident => regExp.test(ident);
124
			}
125
			if (item && typeof item === "object" && typeof item.test === "function") {
126
				return ident => item.test(ident);
127
			}
128
			if (typeof item === "function") {
129
				return item;
130
			}
131
			if (typeof item === "boolean") {
132
				return () => item;
133
			}
134
		};
135

    
136
		const compilation = this.compilation;
137
		const context = optionsOrFallback(
138
			options.context,
139
			compilation.compiler.context
140
		);
141
		const requestShortener =
142
			compilation.compiler.context === context
143
				? compilation.requestShortener
144
				: new RequestShortener(context);
145
		const showPerformance = optionOrLocalFallback(options.performance, true);
146
		const showHash = optionOrLocalFallback(options.hash, true);
147
		const showEnv = optionOrLocalFallback(options.env, false);
148
		const showVersion = optionOrLocalFallback(options.version, true);
149
		const showTimings = optionOrLocalFallback(options.timings, true);
150
		const showBuiltAt = optionOrLocalFallback(options.builtAt, true);
151
		const showAssets = optionOrLocalFallback(options.assets, true);
152
		const showEntrypoints = optionOrLocalFallback(options.entrypoints, true);
153
		const showChunkGroups = optionOrLocalFallback(
154
			options.chunkGroups,
155
			!forToString
156
		);
157
		const showChunks = optionOrLocalFallback(options.chunks, !forToString);
158
		const showChunkModules = optionOrLocalFallback(options.chunkModules, true);
159
		const showChunkOrigins = optionOrLocalFallback(
160
			options.chunkOrigins,
161
			!forToString
162
		);
163
		const showModules = optionOrLocalFallback(options.modules, true);
164
		const showNestedModules = optionOrLocalFallback(
165
			options.nestedModules,
166
			true
167
		);
168
		const showModuleAssets = optionOrLocalFallback(
169
			options.moduleAssets,
170
			!forToString
171
		);
172
		const showDepth = optionOrLocalFallback(options.depth, !forToString);
173
		const showCachedModules = optionOrLocalFallback(options.cached, true);
174
		const showCachedAssets = optionOrLocalFallback(options.cachedAssets, true);
175
		const showReasons = optionOrLocalFallback(options.reasons, !forToString);
176
		const showUsedExports = optionOrLocalFallback(
177
			options.usedExports,
178
			!forToString
179
		);
180
		const showProvidedExports = optionOrLocalFallback(
181
			options.providedExports,
182
			!forToString
183
		);
184
		const showOptimizationBailout = optionOrLocalFallback(
185
			options.optimizationBailout,
186
			!forToString
187
		);
188
		const showChildren = optionOrLocalFallback(options.children, true);
189
		const showSource = optionOrLocalFallback(options.source, !forToString);
190
		const showModuleTrace = optionOrLocalFallback(options.moduleTrace, true);
191
		const showErrors = optionOrLocalFallback(options.errors, true);
192
		const showErrorDetails = optionOrLocalFallback(
193
			options.errorDetails,
194
			!forToString
195
		);
196
		const showWarnings = optionOrLocalFallback(options.warnings, true);
197
		const warningsFilter = optionsOrFallback(options.warningsFilter, null);
198
		const showPublicPath = optionOrLocalFallback(
199
			options.publicPath,
200
			!forToString
201
		);
202
		const showLogging = optionOrLocalFallback(
203
			options.logging,
204
			forToString ? "info" : true
205
		);
206
		const showLoggingTrace = optionOrLocalFallback(
207
			options.loggingTrace,
208
			!forToString
209
		);
210
		const loggingDebug = []
211
			.concat(optionsOrFallback(options.loggingDebug, []))
212
			.map(testAgainstGivenOption);
213

    
214
		const excludeModules = []
215
			.concat(optionsOrFallback(options.excludeModules, options.exclude, []))
216
			.map(testAgainstGivenOption);
217
		const excludeAssets = []
218
			.concat(optionsOrFallback(options.excludeAssets, []))
219
			.map(testAgainstGivenOption);
220
		const maxModules = optionsOrFallback(
221
			options.maxModules,
222
			forToString ? 15 : Infinity
223
		);
224
		const sortModules = optionsOrFallback(options.modulesSort, "id");
225
		const sortChunks = optionsOrFallback(options.chunksSort, "id");
226
		const sortAssets = optionsOrFallback(options.assetsSort, "");
227
		const showOutputPath = optionOrLocalFallback(
228
			options.outputPath,
229
			!forToString
230
		);
231

    
232
		if (!showCachedModules) {
233
			excludeModules.push((ident, module) => !module.built);
234
		}
235

    
236
		const createModuleFilter = () => {
237
			let i = 0;
238
			return module => {
239
				if (excludeModules.length > 0) {
240
					const ident = requestShortener.shorten(module.resource);
241
					const excluded = excludeModules.some(fn => fn(ident, module));
242
					if (excluded) return false;
243
				}
244
				const result = i < maxModules;
245
				i++;
246
				return result;
247
			};
248
		};
249

    
250
		const createAssetFilter = () => {
251
			return asset => {
252
				if (excludeAssets.length > 0) {
253
					const ident = asset.name;
254
					const excluded = excludeAssets.some(fn => fn(ident, asset));
255
					if (excluded) return false;
256
				}
257
				return showCachedAssets || asset.emitted;
258
			};
259
		};
260

    
261
		const sortByFieldAndOrder = (fieldKey, a, b) => {
262
			if (a[fieldKey] === null && b[fieldKey] === null) return 0;
263
			if (a[fieldKey] === null) return 1;
264
			if (b[fieldKey] === null) return -1;
265
			if (a[fieldKey] === b[fieldKey]) return 0;
266
			if (typeof a[fieldKey] !== typeof b[fieldKey])
267
				return typeof a[fieldKey] < typeof b[fieldKey] ? -1 : 1;
268
			return a[fieldKey] < b[fieldKey] ? -1 : 1;
269
		};
270

    
271
		const sortByField = (field, originalArray) => {
272
			const originalMap = originalArray.reduce((map, v, i) => {
273
				map.set(v, i);
274
				return map;
275
			}, new Map());
276
			return (a, b) => {
277
				if (field) {
278
					const fieldKey = this.normalizeFieldKey(field);
279

    
280
					// if a field is prefixed with a "!" the sort is reversed!
281
					const sortIsRegular = this.sortOrderRegular(field);
282

    
283
					const cmp = sortByFieldAndOrder(
284
						fieldKey,
285
						sortIsRegular ? a : b,
286
						sortIsRegular ? b : a
287
					);
288
					if (cmp) return cmp;
289
				}
290
				return originalMap.get(a) - originalMap.get(b);
291
			};
292
		};
293

    
294
		const formatError = e => {
295
			let text = "";
296
			if (typeof e === "string") {
297
				e = { message: e };
298
			}
299
			if (e.chunk) {
300
				text += `chunk ${e.chunk.name || e.chunk.id}${
301
					e.chunk.hasRuntime()
302
						? " [entry]"
303
						: e.chunk.canBeInitial()
304
						? " [initial]"
305
						: ""
306
				}\n`;
307
			}
308
			if (e.file) {
309
				text += `${e.file}\n`;
310
			}
311
			if (
312
				e.module &&
313
				e.module.readableIdentifier &&
314
				typeof e.module.readableIdentifier === "function"
315
			) {
316
				text += this.formatFilePath(
317
					e.module.readableIdentifier(requestShortener)
318
				);
319
				if (typeof e.loc === "object") {
320
					const locInfo = formatLocation(e.loc);
321
					if (locInfo) text += ` ${locInfo}`;
322
				}
323
				text += "\n";
324
			}
325
			text += e.message;
326
			if (showErrorDetails && e.details) {
327
				text += `\n${e.details}`;
328
			}
329
			if (showErrorDetails && e.missing) {
330
				text += e.missing.map(item => `\n[${item}]`).join("");
331
			}
332
			if (showModuleTrace && e.origin) {
333
				text += `\n @ ${this.formatFilePath(
334
					e.origin.readableIdentifier(requestShortener)
335
				)}`;
336
				if (typeof e.originLoc === "object") {
337
					const locInfo = formatLocation(e.originLoc);
338
					if (locInfo) text += ` ${locInfo}`;
339
				}
340
				if (e.dependencies) {
341
					for (const dep of e.dependencies) {
342
						if (!dep.loc) continue;
343
						if (typeof dep.loc === "string") continue;
344
						const locInfo = formatLocation(dep.loc);
345
						if (!locInfo) continue;
346
						text += ` ${locInfo}`;
347
					}
348
				}
349
				let current = e.origin;
350
				while (current.issuer) {
351
					current = current.issuer;
352
					text += `\n @ ${current.readableIdentifier(requestShortener)}`;
353
				}
354
			}
355
			return text;
356
		};
357

    
358
		const obj = {
359
			errors: compilation.errors.map(formatError),
360
			warnings: Stats.filterWarnings(
361
				compilation.warnings.map(formatError),
362
				warningsFilter
363
			)
364
		};
365

    
366
		//We just hint other renderers since actually omitting
367
		//errors/warnings from the JSON would be kind of weird.
368
		Object.defineProperty(obj, "_showWarnings", {
369
			value: showWarnings,
370
			enumerable: false
371
		});
372
		Object.defineProperty(obj, "_showErrors", {
373
			value: showErrors,
374
			enumerable: false
375
		});
376

    
377
		if (showVersion) {
378
			obj.version = require("../package.json").version;
379
		}
380

    
381
		if (showHash) obj.hash = this.hash;
382
		if (showTimings && this.startTime && this.endTime) {
383
			obj.time = this.endTime - this.startTime;
384
		}
385

    
386
		if (showBuiltAt && this.endTime) {
387
			obj.builtAt = this.endTime;
388
		}
389

    
390
		if (showEnv && options._env) {
391
			obj.env = options._env;
392
		}
393

    
394
		if (compilation.needAdditionalPass) {
395
			obj.needAdditionalPass = true;
396
		}
397
		if (showPublicPath) {
398
			obj.publicPath = this.compilation.mainTemplate.getPublicPath({
399
				hash: this.compilation.hash
400
			});
401
		}
402
		if (showOutputPath) {
403
			obj.outputPath = this.compilation.mainTemplate.outputOptions.path;
404
		}
405
		if (showAssets) {
406
			const assetsByFile = {};
407
			const compilationAssets = compilation
408
				.getAssets()
409
				.sort((a, b) => (a.name < b.name ? -1 : 1));
410
			obj.assetsByChunkName = {};
411
			obj.assets = compilationAssets
412
				.map(({ name, source, info }) => {
413
					const obj = {
414
						name,
415
						size: source.size(),
416
						chunks: [],
417
						chunkNames: [],
418
						info,
419
						// TODO webpack 5: remove .emitted
420
						emitted: source.emitted || compilation.emittedAssets.has(name)
421
					};
422

    
423
					if (showPerformance) {
424
						obj.isOverSizeLimit = source.isOverSizeLimit;
425
					}
426

    
427
					assetsByFile[name] = obj;
428
					return obj;
429
				})
430
				.filter(createAssetFilter());
431
			obj.filteredAssets = compilationAssets.length - obj.assets.length;
432

    
433
			for (const chunk of compilation.chunks) {
434
				for (const asset of chunk.files) {
435
					if (assetsByFile[asset]) {
436
						for (const id of chunk.ids) {
437
							assetsByFile[asset].chunks.push(id);
438
						}
439
						if (chunk.name) {
440
							assetsByFile[asset].chunkNames.push(chunk.name);
441
							if (obj.assetsByChunkName[chunk.name]) {
442
								obj.assetsByChunkName[chunk.name] = []
443
									.concat(obj.assetsByChunkName[chunk.name])
444
									.concat([asset]);
445
							} else {
446
								obj.assetsByChunkName[chunk.name] = asset;
447
							}
448
						}
449
					}
450
				}
451
			}
452
			obj.assets.sort(sortByField(sortAssets, obj.assets));
453
		}
454

    
455
		const fnChunkGroup = groupMap => {
456
			const obj = {};
457
			for (const keyValuePair of groupMap) {
458
				const name = keyValuePair[0];
459
				const cg = keyValuePair[1];
460
				const children = cg.getChildrenByOrders();
461
				obj[name] = {
462
					chunks: cg.chunks.map(c => c.id),
463
					assets: cg.chunks.reduce(
464
						(array, c) => array.concat(c.files || []),
465
						[]
466
					),
467
					children: Object.keys(children).reduce((obj, key) => {
468
						const groups = children[key];
469
						obj[key] = groups.map(group => ({
470
							name: group.name,
471
							chunks: group.chunks.map(c => c.id),
472
							assets: group.chunks.reduce(
473
								(array, c) => array.concat(c.files || []),
474
								[]
475
							)
476
						}));
477
						return obj;
478
					}, Object.create(null)),
479
					childAssets: Object.keys(children).reduce((obj, key) => {
480
						const groups = children[key];
481
						obj[key] = Array.from(
482
							groups.reduce((set, group) => {
483
								for (const chunk of group.chunks) {
484
									for (const asset of chunk.files) {
485
										set.add(asset);
486
									}
487
								}
488
								return set;
489
							}, new Set())
490
						);
491
						return obj;
492
					}, Object.create(null))
493
				};
494
				if (showPerformance) {
495
					obj[name].isOverSizeLimit = cg.isOverSizeLimit;
496
				}
497
			}
498

    
499
			return obj;
500
		};
501

    
502
		if (showEntrypoints) {
503
			obj.entrypoints = fnChunkGroup(compilation.entrypoints);
504
		}
505

    
506
		if (showChunkGroups) {
507
			obj.namedChunkGroups = fnChunkGroup(compilation.namedChunkGroups);
508
		}
509

    
510
		const fnModule = module => {
511
			const path = [];
512
			let current = module;
513
			while (current.issuer) {
514
				path.push((current = current.issuer));
515
			}
516
			path.reverse();
517
			const obj = {
518
				id: module.id,
519
				identifier: module.identifier(),
520
				name: module.readableIdentifier(requestShortener),
521
				index: module.index,
522
				index2: module.index2,
523
				size: module.size(),
524
				cacheable: module.buildInfo.cacheable,
525
				built: !!module.built,
526
				optional: module.optional,
527
				prefetched: module.prefetched,
528
				chunks: Array.from(module.chunksIterable, chunk => chunk.id),
529
				issuer: module.issuer && module.issuer.identifier(),
530
				issuerId: module.issuer && module.issuer.id,
531
				issuerName:
532
					module.issuer && module.issuer.readableIdentifier(requestShortener),
533
				issuerPath:
534
					module.issuer &&
535
					path.map(module => ({
536
						id: module.id,
537
						identifier: module.identifier(),
538
						name: module.readableIdentifier(requestShortener),
539
						profile: module.profile
540
					})),
541
				profile: module.profile,
542
				failed: !!module.error,
543
				errors: module.errors ? module.errors.length : 0,
544
				warnings: module.warnings ? module.warnings.length : 0
545
			};
546
			if (showModuleAssets) {
547
				obj.assets = Object.keys(module.buildInfo.assets || {});
548
			}
549
			if (showReasons) {
550
				obj.reasons = module.reasons
551
					.sort((a, b) => {
552
						if (a.module && !b.module) return -1;
553
						if (!a.module && b.module) return 1;
554
						if (a.module && b.module) {
555
							const cmp = compareId(a.module.id, b.module.id);
556
							if (cmp) return cmp;
557
						}
558
						if (a.dependency && !b.dependency) return -1;
559
						if (!a.dependency && b.dependency) return 1;
560
						if (a.dependency && b.dependency) {
561
							const cmp = compareLocations(a.dependency.loc, b.dependency.loc);
562
							if (cmp) return cmp;
563
							if (a.dependency.type < b.dependency.type) return -1;
564
							if (a.dependency.type > b.dependency.type) return 1;
565
						}
566
						return 0;
567
					})
568
					.map(reason => {
569
						const obj = {
570
							moduleId: reason.module ? reason.module.id : null,
571
							moduleIdentifier: reason.module
572
								? reason.module.identifier()
573
								: null,
574
							module: reason.module
575
								? reason.module.readableIdentifier(requestShortener)
576
								: null,
577
							moduleName: reason.module
578
								? reason.module.readableIdentifier(requestShortener)
579
								: null,
580
							type: reason.dependency ? reason.dependency.type : null,
581
							explanation: reason.explanation,
582
							userRequest: reason.dependency
583
								? reason.dependency.userRequest
584
								: null
585
						};
586
						if (reason.dependency) {
587
							const locInfo = formatLocation(reason.dependency.loc);
588
							if (locInfo) {
589
								obj.loc = locInfo;
590
							}
591
						}
592
						return obj;
593
					});
594
			}
595
			if (showUsedExports) {
596
				if (module.used === true) {
597
					obj.usedExports = module.usedExports;
598
				} else if (module.used === false) {
599
					obj.usedExports = false;
600
				}
601
			}
602
			if (showProvidedExports) {
603
				obj.providedExports = Array.isArray(module.buildMeta.providedExports)
604
					? module.buildMeta.providedExports
605
					: null;
606
			}
607
			if (showOptimizationBailout) {
608
				obj.optimizationBailout = module.optimizationBailout.map(item => {
609
					if (typeof item === "function") return item(requestShortener);
610
					return item;
611
				});
612
			}
613
			if (showDepth) {
614
				obj.depth = module.depth;
615
			}
616
			if (showNestedModules) {
617
				if (module.modules) {
618
					const modules = module.modules;
619
					obj.modules = modules
620
						.sort(sortByField("depth", modules))
621
						.filter(createModuleFilter())
622
						.map(fnModule);
623
					obj.filteredModules = modules.length - obj.modules.length;
624
					obj.modules.sort(sortByField(sortModules, obj.modules));
625
				}
626
			}
627
			if (showSource && module._source) {
628
				obj.source = module._source.source();
629
			}
630
			return obj;
631
		};
632
		if (showChunks) {
633
			obj.chunks = compilation.chunks.map(chunk => {
634
				const parents = new Set();
635
				const children = new Set();
636
				const siblings = new Set();
637
				const childIdByOrder = chunk.getChildIdsByOrders();
638
				for (const chunkGroup of chunk.groupsIterable) {
639
					for (const parentGroup of chunkGroup.parentsIterable) {
640
						for (const chunk of parentGroup.chunks) {
641
							parents.add(chunk.id);
642
						}
643
					}
644
					for (const childGroup of chunkGroup.childrenIterable) {
645
						for (const chunk of childGroup.chunks) {
646
							children.add(chunk.id);
647
						}
648
					}
649
					for (const sibling of chunkGroup.chunks) {
650
						if (sibling !== chunk) siblings.add(sibling.id);
651
					}
652
				}
653
				const obj = {
654
					id: chunk.id,
655
					rendered: chunk.rendered,
656
					initial: chunk.canBeInitial(),
657
					entry: chunk.hasRuntime(),
658
					recorded: chunk.recorded,
659
					reason: chunk.chunkReason,
660
					size: chunk.modulesSize(),
661
					names: chunk.name ? [chunk.name] : [],
662
					files: chunk.files.slice(),
663
					hash: chunk.renderedHash,
664
					siblings: Array.from(siblings).sort(compareId),
665
					parents: Array.from(parents).sort(compareId),
666
					children: Array.from(children).sort(compareId),
667
					childrenByOrder: childIdByOrder
668
				};
669
				if (showChunkModules) {
670
					const modules = chunk.getModules();
671
					obj.modules = modules
672
						.slice()
673
						.sort(sortByField("depth", modules))
674
						.filter(createModuleFilter())
675
						.map(fnModule);
676
					obj.filteredModules = chunk.getNumberOfModules() - obj.modules.length;
677
					obj.modules.sort(sortByField(sortModules, obj.modules));
678
				}
679
				if (showChunkOrigins) {
680
					obj.origins = Array.from(chunk.groupsIterable, g => g.origins)
681
						.reduce((a, b) => a.concat(b), [])
682
						.map(origin => ({
683
							moduleId: origin.module ? origin.module.id : undefined,
684
							module: origin.module ? origin.module.identifier() : "",
685
							moduleIdentifier: origin.module ? origin.module.identifier() : "",
686
							moduleName: origin.module
687
								? origin.module.readableIdentifier(requestShortener)
688
								: "",
689
							loc: formatLocation(origin.loc),
690
							request: origin.request,
691
							reasons: origin.reasons || []
692
						}))
693
						.sort((a, b) => {
694
							const cmp1 = compareId(a.moduleId, b.moduleId);
695
							if (cmp1) return cmp1;
696
							const cmp2 = compareId(a.loc, b.loc);
697
							if (cmp2) return cmp2;
698
							const cmp3 = compareId(a.request, b.request);
699
							if (cmp3) return cmp3;
700
							return 0;
701
						});
702
				}
703
				return obj;
704
			});
705
			obj.chunks.sort(sortByField(sortChunks, obj.chunks));
706
		}
707
		if (showModules) {
708
			obj.modules = compilation.modules
709
				.slice()
710
				.sort(sortByField("depth", compilation.modules))
711
				.filter(createModuleFilter())
712
				.map(fnModule);
713
			obj.filteredModules = compilation.modules.length - obj.modules.length;
714
			obj.modules.sort(sortByField(sortModules, obj.modules));
715
		}
716
		if (showLogging) {
717
			const util = require("util");
718
			obj.logging = {};
719
			let acceptedTypes;
720
			let collapsedGroups = false;
721
			switch (showLogging) {
722
				case "none":
723
					acceptedTypes = new Set([]);
724
					break;
725
				case "error":
726
					acceptedTypes = new Set([LogType.error]);
727
					break;
728
				case "warn":
729
					acceptedTypes = new Set([LogType.error, LogType.warn]);
730
					break;
731
				case "info":
732
					acceptedTypes = new Set([LogType.error, LogType.warn, LogType.info]);
733
					break;
734
				case true:
735
				case "log":
736
					acceptedTypes = new Set([
737
						LogType.error,
738
						LogType.warn,
739
						LogType.info,
740
						LogType.log,
741
						LogType.group,
742
						LogType.groupEnd,
743
						LogType.groupCollapsed,
744
						LogType.clear
745
					]);
746
					break;
747
				case "verbose":
748
					acceptedTypes = new Set([
749
						LogType.error,
750
						LogType.warn,
751
						LogType.info,
752
						LogType.log,
753
						LogType.group,
754
						LogType.groupEnd,
755
						LogType.groupCollapsed,
756
						LogType.profile,
757
						LogType.profileEnd,
758
						LogType.time,
759
						LogType.status,
760
						LogType.clear
761
					]);
762
					collapsedGroups = true;
763
					break;
764
			}
765
			for (const [origin, logEntries] of compilation.logging) {
766
				const debugMode = loggingDebug.some(fn => fn(origin));
767
				let collapseCounter = 0;
768
				let processedLogEntries = logEntries;
769
				if (!debugMode) {
770
					processedLogEntries = processedLogEntries.filter(entry => {
771
						if (!acceptedTypes.has(entry.type)) return false;
772
						if (!collapsedGroups) {
773
							switch (entry.type) {
774
								case LogType.groupCollapsed:
775
									collapseCounter++;
776
									return collapseCounter === 1;
777
								case LogType.group:
778
									if (collapseCounter > 0) collapseCounter++;
779
									return collapseCounter === 0;
780
								case LogType.groupEnd:
781
									if (collapseCounter > 0) {
782
										collapseCounter--;
783
										return false;
784
									}
785
									return true;
786
								default:
787
									return collapseCounter === 0;
788
							}
789
						}
790
						return true;
791
					});
792
				}
793
				processedLogEntries = processedLogEntries.map(entry => {
794
					let message = undefined;
795
					if (entry.type === LogType.time) {
796
						message = `${entry.args[0]}: ${entry.args[1] * 1000 +
797
							entry.args[2] / 1000000}ms`;
798
					} else if (entry.args && entry.args.length > 0) {
799
						message = util.format(entry.args[0], ...entry.args.slice(1));
800
					}
801
					return {
802
						type:
803
							(debugMode || collapsedGroups) &&
804
							entry.type === LogType.groupCollapsed
805
								? LogType.group
806
								: entry.type,
807
						message,
808
						trace: showLoggingTrace && entry.trace ? entry.trace : undefined
809
					};
810
				});
811
				let name = identifierUtils
812
					.makePathsRelative(context, origin, compilation.cache)
813
					.replace(/\|/g, " ");
814
				if (name in obj.logging) {
815
					let i = 1;
816
					while (`${name}#${i}` in obj.logging) {
817
						i++;
818
					}
819
					name = `${name}#${i}`;
820
				}
821
				obj.logging[name] = {
822
					entries: processedLogEntries,
823
					filteredEntries: logEntries.length - processedLogEntries.length,
824
					debug: debugMode
825
				};
826
			}
827
		}
828
		if (showChildren) {
829
			obj.children = compilation.children.map((child, idx) => {
830
				const childOptions = Stats.getChildOptions(options, idx);
831
				const obj = new Stats(child).toJson(childOptions, forToString);
832
				delete obj.hash;
833
				delete obj.version;
834
				if (child.name) {
835
					obj.name = identifierUtils.makePathsRelative(
836
						context,
837
						child.name,
838
						compilation.cache
839
					);
840
				}
841
				return obj;
842
			});
843
		}
844

    
845
		return obj;
846
	}
847

    
848
	toString(options) {
849
		if (typeof options === "boolean" || typeof options === "string") {
850
			options = Stats.presetToOptions(options);
851
		} else if (!options) {
852
			options = {};
853
		}
854

    
855
		const useColors = optionsOrFallback(options.colors, false);
856

    
857
		const obj = this.toJson(options, true);
858

    
859
		return Stats.jsonToString(obj, useColors);
860
	}
861

    
862
	static jsonToString(obj, useColors) {
863
		const buf = [];
864

    
865
		const defaultColors = {
866
			bold: "\u001b[1m",
867
			yellow: "\u001b[1m\u001b[33m",
868
			red: "\u001b[1m\u001b[31m",
869
			green: "\u001b[1m\u001b[32m",
870
			cyan: "\u001b[1m\u001b[36m",
871
			magenta: "\u001b[1m\u001b[35m"
872
		};
873

    
874
		const colors = Object.keys(defaultColors).reduce(
875
			(obj, color) => {
876
				obj[color] = str => {
877
					if (useColors) {
878
						buf.push(
879
							useColors === true || useColors[color] === undefined
880
								? defaultColors[color]
881
								: useColors[color]
882
						);
883
					}
884
					buf.push(str);
885
					if (useColors) {
886
						buf.push("\u001b[39m\u001b[22m");
887
					}
888
				};
889
				return obj;
890
			},
891
			{
892
				normal: str => buf.push(str)
893
			}
894
		);
895

    
896
		const coloredTime = time => {
897
			let times = [800, 400, 200, 100];
898
			if (obj.time) {
899
				times = [obj.time / 2, obj.time / 4, obj.time / 8, obj.time / 16];
900
			}
901
			if (time < times[3]) colors.normal(`${time}ms`);
902
			else if (time < times[2]) colors.bold(`${time}ms`);
903
			else if (time < times[1]) colors.green(`${time}ms`);
904
			else if (time < times[0]) colors.yellow(`${time}ms`);
905
			else colors.red(`${time}ms`);
906
		};
907

    
908
		const newline = () => buf.push("\n");
909

    
910
		const getText = (arr, row, col) => {
911
			return arr[row][col].value;
912
		};
913

    
914
		const table = (array, align, splitter) => {
915
			const rows = array.length;
916
			const cols = array[0].length;
917
			const colSizes = new Array(cols);
918
			for (let col = 0; col < cols; col++) {
919
				colSizes[col] = 0;
920
			}
921
			for (let row = 0; row < rows; row++) {
922
				for (let col = 0; col < cols; col++) {
923
					const value = `${getText(array, row, col)}`;
924
					if (value.length > colSizes[col]) {
925
						colSizes[col] = value.length;
926
					}
927
				}
928
			}
929
			for (let row = 0; row < rows; row++) {
930
				for (let col = 0; col < cols; col++) {
931
					const format = array[row][col].color;
932
					const value = `${getText(array, row, col)}`;
933
					let l = value.length;
934
					if (align[col] === "l") {
935
						format(value);
936
					}
937
					for (; l < colSizes[col] && col !== cols - 1; l++) {
938
						colors.normal(" ");
939
					}
940
					if (align[col] === "r") {
941
						format(value);
942
					}
943
					if (col + 1 < cols && colSizes[col] !== 0) {
944
						colors.normal(splitter || "  ");
945
					}
946
				}
947
				newline();
948
			}
949
		};
950

    
951
		const getAssetColor = (asset, defaultColor) => {
952
			if (asset.isOverSizeLimit) {
953
				return colors.yellow;
954
			}
955

    
956
			return defaultColor;
957
		};
958

    
959
		if (obj.hash) {
960
			colors.normal("Hash: ");
961
			colors.bold(obj.hash);
962
			newline();
963
		}
964
		if (obj.version) {
965
			colors.normal("Version: webpack ");
966
			colors.bold(obj.version);
967
			newline();
968
		}
969
		if (typeof obj.time === "number") {
970
			colors.normal("Time: ");
971
			colors.bold(obj.time);
972
			colors.normal("ms");
973
			newline();
974
		}
975
		if (typeof obj.builtAt === "number") {
976
			const builtAtDate = new Date(obj.builtAt);
977
			let timeZone = undefined;
978

    
979
			try {
980
				builtAtDate.toLocaleTimeString();
981
			} catch (err) {
982
				// Force UTC if runtime timezone is unsupported
983
				timeZone = "UTC";
984
			}
985

    
986
			colors.normal("Built at: ");
987
			colors.normal(
988
				builtAtDate.toLocaleDateString(undefined, {
989
					day: "2-digit",
990
					month: "2-digit",
991
					year: "numeric",
992
					timeZone
993
				})
994
			);
995
			colors.normal(" ");
996
			colors.bold(builtAtDate.toLocaleTimeString(undefined, { timeZone }));
997
			newline();
998
		}
999
		if (obj.env) {
1000
			colors.normal("Environment (--env): ");
1001
			colors.bold(JSON.stringify(obj.env, null, 2));
1002
			newline();
1003
		}
1004
		if (obj.publicPath) {
1005
			colors.normal("PublicPath: ");
1006
			colors.bold(obj.publicPath);
1007
			newline();
1008
		}
1009

    
1010
		if (obj.assets && obj.assets.length > 0) {
1011
			const t = [
1012
				[
1013
					{
1014
						value: "Asset",
1015
						color: colors.bold
1016
					},
1017
					{
1018
						value: "Size",
1019
						color: colors.bold
1020
					},
1021
					{
1022
						value: "Chunks",
1023
						color: colors.bold
1024
					},
1025
					{
1026
						value: "",
1027
						color: colors.bold
1028
					},
1029
					{
1030
						value: "",
1031
						color: colors.bold
1032
					},
1033
					{
1034
						value: "Chunk Names",
1035
						color: colors.bold
1036
					}
1037
				]
1038
			];
1039
			for (const asset of obj.assets) {
1040
				t.push([
1041
					{
1042
						value: asset.name,
1043
						color: getAssetColor(asset, colors.green)
1044
					},
1045
					{
1046
						value: SizeFormatHelpers.formatSize(asset.size),
1047
						color: getAssetColor(asset, colors.normal)
1048
					},
1049
					{
1050
						value: asset.chunks.join(", "),
1051
						color: colors.bold
1052
					},
1053
					{
1054
						value: [
1055
							asset.emitted && "[emitted]",
1056
							asset.info.immutable && "[immutable]",
1057
							asset.info.development && "[dev]",
1058
							asset.info.hotModuleReplacement && "[hmr]"
1059
						]
1060
							.filter(Boolean)
1061
							.join(" "),
1062
						color: colors.green
1063
					},
1064
					{
1065
						value: asset.isOverSizeLimit ? "[big]" : "",
1066
						color: getAssetColor(asset, colors.normal)
1067
					},
1068
					{
1069
						value: asset.chunkNames.join(", "),
1070
						color: colors.normal
1071
					}
1072
				]);
1073
			}
1074
			table(t, "rrrlll");
1075
		}
1076
		if (obj.filteredAssets > 0) {
1077
			colors.normal(" ");
1078
			if (obj.assets.length > 0) colors.normal("+ ");
1079
			colors.normal(obj.filteredAssets);
1080
			if (obj.assets.length > 0) colors.normal(" hidden");
1081
			colors.normal(obj.filteredAssets !== 1 ? " assets" : " asset");
1082
			newline();
1083
		}
1084

    
1085
		const processChunkGroups = (namedGroups, prefix) => {
1086
			for (const name of Object.keys(namedGroups)) {
1087
				const cg = namedGroups[name];
1088
				colors.normal(`${prefix} `);
1089
				colors.bold(name);
1090
				if (cg.isOverSizeLimit) {
1091
					colors.normal(" ");
1092
					colors.yellow("[big]");
1093
				}
1094
				colors.normal(" =");
1095
				for (const asset of cg.assets) {
1096
					colors.normal(" ");
1097
					colors.green(asset);
1098
				}
1099
				for (const name of Object.keys(cg.childAssets)) {
1100
					const assets = cg.childAssets[name];
1101
					if (assets && assets.length > 0) {
1102
						colors.normal(" ");
1103
						colors.magenta(`(${name}:`);
1104
						for (const asset of assets) {
1105
							colors.normal(" ");
1106
							colors.green(asset);
1107
						}
1108
						colors.magenta(")");
1109
					}
1110
				}
1111
				newline();
1112
			}
1113
		};
1114

    
1115
		if (obj.entrypoints) {
1116
			processChunkGroups(obj.entrypoints, "Entrypoint");
1117
		}
1118

    
1119
		if (obj.namedChunkGroups) {
1120
			let outputChunkGroups = obj.namedChunkGroups;
1121
			if (obj.entrypoints) {
1122
				outputChunkGroups = Object.keys(outputChunkGroups)
1123
					.filter(name => !obj.entrypoints[name])
1124
					.reduce((result, name) => {
1125
						result[name] = obj.namedChunkGroups[name];
1126
						return result;
1127
					}, {});
1128
			}
1129
			processChunkGroups(outputChunkGroups, "Chunk Group");
1130
		}
1131

    
1132
		const modulesByIdentifier = {};
1133
		if (obj.modules) {
1134
			for (const module of obj.modules) {
1135
				modulesByIdentifier[`$${module.identifier}`] = module;
1136
			}
1137
		} else if (obj.chunks) {
1138
			for (const chunk of obj.chunks) {
1139
				if (chunk.modules) {
1140
					for (const module of chunk.modules) {
1141
						modulesByIdentifier[`$${module.identifier}`] = module;
1142
					}
1143
				}
1144
			}
1145
		}
1146

    
1147
		const processModuleAttributes = module => {
1148
			colors.normal(" ");
1149
			colors.normal(SizeFormatHelpers.formatSize(module.size));
1150
			if (module.chunks) {
1151
				for (const chunk of module.chunks) {
1152
					colors.normal(" {");
1153
					colors.yellow(chunk);
1154
					colors.normal("}");
1155
				}
1156
			}
1157
			if (typeof module.depth === "number") {
1158
				colors.normal(` [depth ${module.depth}]`);
1159
			}
1160
			if (module.cacheable === false) {
1161
				colors.red(" [not cacheable]");
1162
			}
1163
			if (module.optional) {
1164
				colors.yellow(" [optional]");
1165
			}
1166
			if (module.built) {
1167
				colors.green(" [built]");
1168
			}
1169
			if (module.assets && module.assets.length) {
1170
				colors.magenta(
1171
					` [${module.assets.length} asset${
1172
						module.assets.length === 1 ? "" : "s"
1173
					}]`
1174
				);
1175
			}
1176
			if (module.prefetched) {
1177
				colors.magenta(" [prefetched]");
1178
			}
1179
			if (module.failed) colors.red(" [failed]");
1180
			if (module.warnings) {
1181
				colors.yellow(
1182
					` [${module.warnings} warning${module.warnings === 1 ? "" : "s"}]`
1183
				);
1184
			}
1185
			if (module.errors) {
1186
				colors.red(
1187
					` [${module.errors} error${module.errors === 1 ? "" : "s"}]`
1188
				);
1189
			}
1190
		};
1191

    
1192
		const processModuleContent = (module, prefix) => {
1193
			if (Array.isArray(module.providedExports)) {
1194
				colors.normal(prefix);
1195
				if (module.providedExports.length === 0) {
1196
					colors.cyan("[no exports]");
1197
				} else {
1198
					colors.cyan(`[exports: ${module.providedExports.join(", ")}]`);
1199
				}
1200
				newline();
1201
			}
1202
			if (module.usedExports !== undefined) {
1203
				if (module.usedExports !== true) {
1204
					colors.normal(prefix);
1205
					if (module.usedExports === null) {
1206
						colors.cyan("[used exports unknown]");
1207
					} else if (module.usedExports === false) {
1208
						colors.cyan("[no exports used]");
1209
					} else if (
1210
						Array.isArray(module.usedExports) &&
1211
						module.usedExports.length === 0
1212
					) {
1213
						colors.cyan("[no exports used]");
1214
					} else if (Array.isArray(module.usedExports)) {
1215
						const providedExportsCount = Array.isArray(module.providedExports)
1216
							? module.providedExports.length
1217
							: null;
1218
						if (
1219
							providedExportsCount !== null &&
1220
							providedExportsCount === module.usedExports.length
1221
						) {
1222
							colors.cyan("[all exports used]");
1223
						} else {
1224
							colors.cyan(
1225
								`[only some exports used: ${module.usedExports.join(", ")}]`
1226
							);
1227
						}
1228
					}
1229
					newline();
1230
				}
1231
			}
1232
			if (Array.isArray(module.optimizationBailout)) {
1233
				for (const item of module.optimizationBailout) {
1234
					colors.normal(prefix);
1235
					colors.yellow(item);
1236
					newline();
1237
				}
1238
			}
1239
			if (module.reasons) {
1240
				for (const reason of module.reasons) {
1241
					colors.normal(prefix);
1242
					if (reason.type) {
1243
						colors.normal(reason.type);
1244
						colors.normal(" ");
1245
					}
1246
					if (reason.userRequest) {
1247
						colors.cyan(reason.userRequest);
1248
						colors.normal(" ");
1249
					}
1250
					if (reason.moduleId !== null) {
1251
						colors.normal("[");
1252
						colors.normal(reason.moduleId);
1253
						colors.normal("]");
1254
					}
1255
					if (reason.module && reason.module !== reason.moduleId) {
1256
						colors.normal(" ");
1257
						colors.magenta(reason.module);
1258
					}
1259
					if (reason.loc) {
1260
						colors.normal(" ");
1261
						colors.normal(reason.loc);
1262
					}
1263
					if (reason.explanation) {
1264
						colors.normal(" ");
1265
						colors.cyan(reason.explanation);
1266
					}
1267
					newline();
1268
				}
1269
			}
1270
			if (module.profile) {
1271
				colors.normal(prefix);
1272
				let sum = 0;
1273
				if (module.issuerPath) {
1274
					for (const m of module.issuerPath) {
1275
						colors.normal("[");
1276
						colors.normal(m.id);
1277
						colors.normal("] ");
1278
						if (m.profile) {
1279
							const time = (m.profile.factory || 0) + (m.profile.building || 0);
1280
							coloredTime(time);
1281
							sum += time;
1282
							colors.normal(" ");
1283
						}
1284
						colors.normal("-> ");
1285
					}
1286
				}
1287
				for (const key of Object.keys(module.profile)) {
1288
					colors.normal(`${key}:`);
1289
					const time = module.profile[key];
1290
					coloredTime(time);
1291
					colors.normal(" ");
1292
					sum += time;
1293
				}
1294
				colors.normal("= ");
1295
				coloredTime(sum);
1296
				newline();
1297
			}
1298
			if (module.modules) {
1299
				processModulesList(module, prefix + "| ");
1300
			}
1301
		};
1302

    
1303
		const processModulesList = (obj, prefix) => {
1304
			if (obj.modules) {
1305
				let maxModuleId = 0;
1306
				for (const module of obj.modules) {
1307
					if (typeof module.id === "number") {
1308
						if (maxModuleId < module.id) maxModuleId = module.id;
1309
					}
1310
				}
1311
				let contentPrefix = prefix + "    ";
1312
				if (maxModuleId >= 10) contentPrefix += " ";
1313
				if (maxModuleId >= 100) contentPrefix += " ";
1314
				if (maxModuleId >= 1000) contentPrefix += " ";
1315
				for (const module of obj.modules) {
1316
					colors.normal(prefix);
1317
					const name = module.name || module.identifier;
1318
					if (typeof module.id === "string" || typeof module.id === "number") {
1319
						if (typeof module.id === "number") {
1320
							if (module.id < 1000 && maxModuleId >= 1000) colors.normal(" ");
1321
							if (module.id < 100 && maxModuleId >= 100) colors.normal(" ");
1322
							if (module.id < 10 && maxModuleId >= 10) colors.normal(" ");
1323
						} else {
1324
							if (maxModuleId >= 1000) colors.normal(" ");
1325
							if (maxModuleId >= 100) colors.normal(" ");
1326
							if (maxModuleId >= 10) colors.normal(" ");
1327
						}
1328
						if (name !== module.id) {
1329
							colors.normal("[");
1330
							colors.normal(module.id);
1331
							colors.normal("]");
1332
							colors.normal(" ");
1333
						} else {
1334
							colors.normal("[");
1335
							colors.bold(module.id);
1336
							colors.normal("]");
1337
						}
1338
					}
1339
					if (name !== module.id) {
1340
						colors.bold(name);
1341
					}
1342
					processModuleAttributes(module);
1343
					newline();
1344
					processModuleContent(module, contentPrefix);
1345
				}
1346
				if (obj.filteredModules > 0) {
1347
					colors.normal(prefix);
1348
					colors.normal("   ");
1349
					if (obj.modules.length > 0) colors.normal(" + ");
1350
					colors.normal(obj.filteredModules);
1351
					if (obj.modules.length > 0) colors.normal(" hidden");
1352
					colors.normal(obj.filteredModules !== 1 ? " modules" : " module");
1353
					newline();
1354
				}
1355
			}
1356
		};
1357

    
1358
		if (obj.chunks) {
1359
			for (const chunk of obj.chunks) {
1360
				colors.normal("chunk ");
1361
				if (chunk.id < 1000) colors.normal(" ");
1362
				if (chunk.id < 100) colors.normal(" ");
1363
				if (chunk.id < 10) colors.normal(" ");
1364
				colors.normal("{");
1365
				colors.yellow(chunk.id);
1366
				colors.normal("} ");
1367
				colors.green(chunk.files.join(", "));
1368
				if (chunk.names && chunk.names.length > 0) {
1369
					colors.normal(" (");
1370
					colors.normal(chunk.names.join(", "));
1371
					colors.normal(")");
1372
				}
1373
				colors.normal(" ");
1374
				colors.normal(SizeFormatHelpers.formatSize(chunk.size));
1375
				for (const id of chunk.parents) {
1376
					colors.normal(" <{");
1377
					colors.yellow(id);
1378
					colors.normal("}>");
1379
				}
1380
				for (const id of chunk.siblings) {
1381
					colors.normal(" ={");
1382
					colors.yellow(id);
1383
					colors.normal("}=");
1384
				}
1385
				for (const id of chunk.children) {
1386
					colors.normal(" >{");
1387
					colors.yellow(id);
1388
					colors.normal("}<");
1389
				}
1390
				if (chunk.childrenByOrder) {
1391
					for (const name of Object.keys(chunk.childrenByOrder)) {
1392
						const children = chunk.childrenByOrder[name];
1393
						colors.normal(" ");
1394
						colors.magenta(`(${name}:`);
1395
						for (const id of children) {
1396
							colors.normal(" {");
1397
							colors.yellow(id);
1398
							colors.normal("}");
1399
						}
1400
						colors.magenta(")");
1401
					}
1402
				}
1403
				if (chunk.entry) {
1404
					colors.yellow(" [entry]");
1405
				} else if (chunk.initial) {
1406
					colors.yellow(" [initial]");
1407
				}
1408
				if (chunk.rendered) {
1409
					colors.green(" [rendered]");
1410
				}
1411
				if (chunk.recorded) {
1412
					colors.green(" [recorded]");
1413
				}
1414
				if (chunk.reason) {
1415
					colors.yellow(` ${chunk.reason}`);
1416
				}
1417
				newline();
1418
				if (chunk.origins) {
1419
					for (const origin of chunk.origins) {
1420
						colors.normal("    > ");
1421
						if (origin.reasons && origin.reasons.length) {
1422
							colors.yellow(origin.reasons.join(" "));
1423
							colors.normal(" ");
1424
						}
1425
						if (origin.request) {
1426
							colors.normal(origin.request);
1427
							colors.normal(" ");
1428
						}
1429
						if (origin.module) {
1430
							colors.normal("[");
1431
							colors.normal(origin.moduleId);
1432
							colors.normal("] ");
1433
							const module = modulesByIdentifier[`$${origin.module}`];
1434
							if (module) {
1435
								colors.bold(module.name);
1436
								colors.normal(" ");
1437
							}
1438
						}
1439
						if (origin.loc) {
1440
							colors.normal(origin.loc);
1441
						}
1442
						newline();
1443
					}
1444
				}
1445
				processModulesList(chunk, " ");
1446
			}
1447
		}
1448

    
1449
		processModulesList(obj, "");
1450

    
1451
		if (obj.logging) {
1452
			for (const origin of Object.keys(obj.logging)) {
1453
				const logData = obj.logging[origin];
1454
				if (logData.entries.length > 0) {
1455
					newline();
1456
					if (logData.debug) {
1457
						colors.red("DEBUG ");
1458
					}
1459
					colors.bold("LOG from " + origin);
1460
					newline();
1461
					let indent = "";
1462
					for (const entry of logData.entries) {
1463
						let color = colors.normal;
1464
						let prefix = "    ";
1465
						switch (entry.type) {
1466
							case LogType.clear:
1467
								colors.normal(`${indent}-------`);
1468
								newline();
1469
								continue;
1470
							case LogType.error:
1471
								color = colors.red;
1472
								prefix = "<e> ";
1473
								break;
1474
							case LogType.warn:
1475
								color = colors.yellow;
1476
								prefix = "<w> ";
1477
								break;
1478
							case LogType.info:
1479
								color = colors.green;
1480
								prefix = "<i> ";
1481
								break;
1482
							case LogType.log:
1483
								color = colors.bold;
1484
								break;
1485
							case LogType.trace:
1486
							case LogType.debug:
1487
								color = colors.normal;
1488
								break;
1489
							case LogType.status:
1490
								color = colors.magenta;
1491
								prefix = "<s> ";
1492
								break;
1493
							case LogType.profile:
1494
								color = colors.magenta;
1495
								prefix = "<p> ";
1496
								break;
1497
							case LogType.profileEnd:
1498
								color = colors.magenta;
1499
								prefix = "</p> ";
1500
								break;
1501
							case LogType.time:
1502
								color = colors.magenta;
1503
								prefix = "<t> ";
1504
								break;
1505
							case LogType.group:
1506
								color = colors.cyan;
1507
								prefix = "<-> ";
1508
								break;
1509
							case LogType.groupCollapsed:
1510
								color = colors.cyan;
1511
								prefix = "<+> ";
1512
								break;
1513
							case LogType.groupEnd:
1514
								if (indent.length >= 2)
1515
									indent = indent.slice(0, indent.length - 2);
1516
								continue;
1517
						}
1518
						if (entry.message) {
1519
							for (const line of entry.message.split("\n")) {
1520
								colors.normal(`${indent}${prefix}`);
1521
								color(line);
1522
								newline();
1523
							}
1524
						}
1525
						if (entry.trace) {
1526
							for (const line of entry.trace) {
1527
								colors.normal(`${indent}| ${line}`);
1528
								newline();
1529
							}
1530
						}
1531
						switch (entry.type) {
1532
							case LogType.group:
1533
								indent += "  ";
1534
								break;
1535
						}
1536
					}
1537
					if (logData.filteredEntries) {
1538
						colors.normal(`+ ${logData.filteredEntries} hidden lines`);
1539
						newline();
1540
					}
1541
				}
1542
			}
1543
		}
1544

    
1545
		if (obj._showWarnings && obj.warnings) {
1546
			for (const warning of obj.warnings) {
1547
				newline();
1548
				colors.yellow(`WARNING in ${warning}`);
1549
				newline();
1550
			}
1551
		}
1552
		if (obj._showErrors && obj.errors) {
1553
			for (const error of obj.errors) {
1554
				newline();
1555
				colors.red(`ERROR in ${error}`);
1556
				newline();
1557
			}
1558
		}
1559
		if (obj.children) {
1560
			for (const child of obj.children) {
1561
				const childString = Stats.jsonToString(child, useColors);
1562
				if (childString) {
1563
					if (child.name) {
1564
						colors.normal("Child ");
1565
						colors.bold(child.name);
1566
						colors.normal(":");
1567
					} else {
1568
						colors.normal("Child");
1569
					}
1570
					newline();
1571
					buf.push("    ");
1572
					buf.push(childString.replace(/\n/g, "\n    "));
1573
					newline();
1574
				}
1575
			}
1576
		}
1577
		if (obj.needAdditionalPass) {
1578
			colors.yellow(
1579
				"Compilation needs an additional pass and will compile again."
1580
			);
1581
		}
1582

    
1583
		while (buf[buf.length - 1] === "\n") {
1584
			buf.pop();
1585
		}
1586
		return buf.join("");
1587
	}
1588

    
1589
	static presetToOptions(name) {
1590
		// Accepted values: none, errors-only, minimal, normal, detailed, verbose
1591
		// Any other falsy value will behave as 'none', truthy values as 'normal'
1592
		const pn =
1593
			(typeof name === "string" && name.toLowerCase()) || name || "none";
1594
		switch (pn) {
1595
			case "none":
1596
				return {
1597
					all: false
1598
				};
1599
			case "verbose":
1600
				return {
1601
					entrypoints: true,
1602
					chunkGroups: true,
1603
					modules: false,
1604
					chunks: true,
1605
					chunkModules: true,
1606
					chunkOrigins: true,
1607
					depth: true,
1608
					env: true,
1609
					reasons: true,
1610
					usedExports: true,
1611
					providedExports: true,
1612
					optimizationBailout: true,
1613
					errorDetails: true,
1614
					publicPath: true,
1615
					logging: "verbose",
1616
					exclude: false,
1617
					maxModules: Infinity
1618
				};
1619
			case "detailed":
1620
				return {
1621
					entrypoints: true,
1622
					chunkGroups: true,
1623
					chunks: true,
1624
					chunkModules: false,
1625
					chunkOrigins: true,
1626
					depth: true,
1627
					usedExports: true,
1628
					providedExports: true,
1629
					optimizationBailout: true,
1630
					errorDetails: true,
1631
					publicPath: true,
1632
					logging: true,
1633
					exclude: false,
1634
					maxModules: Infinity
1635
				};
1636
			case "minimal":
1637
				return {
1638
					all: false,
1639
					modules: true,
1640
					maxModules: 0,
1641
					errors: true,
1642
					warnings: true,
1643
					logging: "warn"
1644
				};
1645
			case "errors-only":
1646
				return {
1647
					all: false,
1648
					errors: true,
1649
					moduleTrace: true,
1650
					logging: "error"
1651
				};
1652
			case "errors-warnings":
1653
				return {
1654
					all: false,
1655
					errors: true,
1656
					warnings: true,
1657
					logging: "warn"
1658
				};
1659
			default:
1660
				return {};
1661
		}
1662
	}
1663

    
1664
	static getChildOptions(options, idx) {
1665
		let innerOptions;
1666
		if (Array.isArray(options.children)) {
1667
			if (idx < options.children.length) {
1668
				innerOptions = options.children[idx];
1669
			}
1670
		} else if (typeof options.children === "object" && options.children) {
1671
			innerOptions = options.children;
1672
		}
1673
		if (typeof innerOptions === "boolean" || typeof innerOptions === "string") {
1674
			innerOptions = Stats.presetToOptions(innerOptions);
1675
		}
1676
		if (!innerOptions) {
1677
			return options;
1678
		}
1679
		const childOptions = Object.assign({}, options);
1680
		delete childOptions.children; // do not inherit children
1681
		return Object.assign(childOptions, innerOptions);
1682
	}
1683
}
1684

    
1685
module.exports = Stats;
(125-125/145)