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

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

Fix frontend appearance

  • Property mode set to 100644
File size: 10.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 { HookMap, SyncBailHook, SyncWaterfallHook } = require("tapable");
9
10/** @typedef {import("./DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
11/** @typedef {import("./DefaultStatsFactoryPlugin").StatsChunk} StatsChunk */
12/** @typedef {import("./DefaultStatsFactoryPlugin").StatsChunkGroup} StatsChunkGroup */
13/** @typedef {import("./DefaultStatsFactoryPlugin").StatsCompilation} StatsCompilation */
14/** @typedef {import("./DefaultStatsFactoryPlugin").StatsError} StatsError */
15/** @typedef {import("./DefaultStatsFactoryPlugin").StatsLogging} StatsLogging */
16/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModule} StatsModule */
17/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleIssuer} StatsModuleIssuer */
18/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleReason} StatsModuleReason */
19/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleTraceDependency} StatsModuleTraceDependency */
20/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleTraceItem} StatsModuleTraceItem */
21/** @typedef {import("./DefaultStatsFactoryPlugin").StatsProfile} StatsProfile */
22
23/**
24 * Defines the printed element type used by this module.
25 * @typedef {object} PrintedElement
26 * @property {string} element
27 * @property {string | undefined} content
28 */
29
30/**
31 * Defines the known stats printer context type used by this module.
32 * @typedef {object} KnownStatsPrinterContext
33 * @property {string=} type
34 * @property {StatsCompilation=} compilation
35 * @property {StatsChunkGroup=} chunkGroup
36 * @property {string=} chunkGroupKind
37 * @property {StatsAsset=} asset
38 * @property {StatsModule=} module
39 * @property {StatsChunk=} chunk
40 * @property {StatsModuleReason=} moduleReason
41 * @property {StatsModuleIssuer=} moduleIssuer
42 * @property {StatsError=} error
43 * @property {StatsProfile=} profile
44 * @property {StatsLogging=} logging
45 * @property {StatsModuleTraceItem=} moduleTraceItem
46 * @property {StatsModuleTraceDependency=} moduleTraceDependency
47 */
48
49/** @typedef {(value: string | number) => string} ColorFunction */
50
51/**
52 * Defines the known stats printer color functions type used by this module.
53 * @typedef {object} KnownStatsPrinterColorFunctions
54 * @property {ColorFunction=} bold
55 * @property {ColorFunction=} yellow
56 * @property {ColorFunction=} red
57 * @property {ColorFunction=} green
58 * @property {ColorFunction=} magenta
59 * @property {ColorFunction=} cyan
60 */
61
62/**
63 * Defines the known stats printer formatters type used by this module.
64 * @typedef {object} KnownStatsPrinterFormatters
65 * @property {(file: string, oversize?: boolean) => string=} formatFilename
66 * @property {(id: string | number) => string=} formatModuleId
67 * @property {(id: string | number, direction?: "parent" | "child" | "sibling") => string=} formatChunkId
68 * @property {(size: number) => string=} formatSize
69 * @property {(size: string) => string=} formatLayer
70 * @property {(dateTime: number) => string=} formatDateTime
71 * @property {(flag: string) => string=} formatFlag
72 * @property {(time: number, boldQuantity?: boolean) => string=} formatTime
73 * @property {(message: string) => string=} formatError
74 */
75
76/** @typedef {KnownStatsPrinterColorFunctions & KnownStatsPrinterFormatters & KnownStatsPrinterContext & Record<string, EXPECTED_ANY>} StatsPrinterContext */
77/** @typedef {StatsPrinterContext & Required<KnownStatsPrinterColorFunctions> & Required<KnownStatsPrinterFormatters> & { type: string }} StatsPrinterContextWithExtra */
78/** @typedef {EXPECTED_ANY} PrintObject */
79
80/**
81 * Represents the stats printer runtime component.
82 * @typedef {object} StatsPrintHooks
83 * @property {HookMap<SyncBailHook<[string[], StatsPrinterContext], void>>} sortElements
84 * @property {HookMap<SyncBailHook<[PrintedElement[], StatsPrinterContext], string | undefined | void>>} printElements
85 * @property {HookMap<SyncBailHook<[PrintObject[], StatsPrinterContext], boolean | void>>} sortItems
86 * @property {HookMap<SyncBailHook<[PrintObject, StatsPrinterContext], string | void>>} getItemName
87 * @property {HookMap<SyncBailHook<[string[], StatsPrinterContext], string | undefined>>} printItems
88 * @property {HookMap<SyncBailHook<[PrintObject, StatsPrinterContext], string | undefined | void>>} print
89 * @property {HookMap<SyncWaterfallHook<[string, StatsPrinterContext]>>} result
90 */
91
92class StatsPrinter {
93 constructor() {
94 /** @type {StatsPrintHooks} */
95 this.hooks = Object.freeze({
96 sortElements: new HookMap(
97 () => new SyncBailHook(["elements", "context"])
98 ),
99 printElements: new HookMap(
100 () => new SyncBailHook(["printedElements", "context"])
101 ),
102 sortItems: new HookMap(() => new SyncBailHook(["items", "context"])),
103 getItemName: new HookMap(() => new SyncBailHook(["item", "context"])),
104 printItems: new HookMap(
105 () => new SyncBailHook(["printedItems", "context"])
106 ),
107 print: new HookMap(() => new SyncBailHook(["object", "context"])),
108 result: new HookMap(() => new SyncWaterfallHook(["result", "context"]))
109 });
110 /** @type {Map<StatsPrintHooks[keyof StatsPrintHooks], Map<string, import("tapable").Hook<EXPECTED_ANY, EXPECTED_ANY>[]>>} */
111 this._levelHookCache = new Map();
112 this._inPrint = false;
113 }
114
115 /**
116 * get all level hooks
117 * @private
118 * @template {StatsPrintHooks[keyof StatsPrintHooks]} HM
119 * @template {HM extends HookMap<infer H> ? H : never} H
120 * @param {HM} hookMap hook map
121 * @param {string} type type
122 * @returns {H[]} hooks
123 */
124 _getAllLevelHooks(hookMap, type) {
125 let cache = this._levelHookCache.get(hookMap);
126 if (cache === undefined) {
127 cache = new Map();
128 this._levelHookCache.set(hookMap, cache);
129 }
130 const cacheEntry = cache.get(type);
131 if (cacheEntry !== undefined) {
132 return /** @type {H[]} */ (cacheEntry);
133 }
134 /** @type {H[]} */
135 const hooks = [];
136 const typeParts = type.split(".");
137 for (let i = 0; i < typeParts.length; i++) {
138 const hook = /** @type {H} */ (hookMap.get(typeParts.slice(i).join(".")));
139 if (hook) {
140 hooks.push(hook);
141 }
142 }
143 cache.set(type, hooks);
144 return hooks;
145 }
146
147 /**
148 * Run `fn` for each level
149 * @private
150 * @template {StatsPrintHooks[keyof StatsPrintHooks]} HM
151 * @template {HM extends HookMap<infer H> ? H : never} H
152 * @template {H extends import("tapable").Hook<EXPECTED_ANY, infer R> ? R : never} R
153 * @param {HM} hookMap hook map
154 * @param {string} type type
155 * @param {(hooK: H) => R | undefined | void} fn fn
156 * @returns {R | undefined} hook
157 */
158 _forEachLevel(hookMap, type, fn) {
159 for (const hook of this._getAllLevelHooks(hookMap, type)) {
160 const result = fn(/** @type {H} */ (hook));
161 if (result !== undefined) return /** @type {R} */ (result);
162 }
163 }
164
165 /**
166 * Run `fn` for each level
167 * @private
168 * @template {StatsPrintHooks[keyof StatsPrintHooks]} HM
169 * @template {HM extends HookMap<infer H> ? H : never} H
170 * @param {HM} hookMap hook map
171 * @param {string} type type
172 * @param {string} data data
173 * @param {(hook: H, data: string) => string} fn fn
174 * @returns {string | undefined} result of `fn`
175 */
176 _forEachLevelWaterfall(hookMap, type, data, fn) {
177 for (const hook of this._getAllLevelHooks(hookMap, type)) {
178 data = fn(/** @type {H} */ (hook), data);
179 }
180 return data;
181 }
182
183 /**
184 * Returns printed result.
185 * @param {string} type The type
186 * @param {PrintObject} object Object to print
187 * @param {StatsPrinterContext=} baseContext The base context
188 * @returns {string | undefined} printed result
189 */
190 print(type, object, baseContext) {
191 if (this._inPrint) {
192 return this._print(type, object, baseContext);
193 }
194 try {
195 this._inPrint = true;
196 return this._print(type, object, baseContext);
197 } finally {
198 this._levelHookCache.clear();
199 this._inPrint = false;
200 }
201 }
202
203 /**
204 * Returns printed result.
205 * @private
206 * @param {string} type type
207 * @param {PrintObject} object object
208 * @param {StatsPrinterContext=} baseContext context
209 * @returns {string | undefined} printed result
210 */
211 _print(type, object, baseContext) {
212 /** @type {StatsPrinterContext} */
213 const context = {
214 ...baseContext,
215 type,
216 [type]: object
217 };
218
219 /** @type {string | undefined} */
220 let printResult = this._forEachLevel(this.hooks.print, type, (hook) =>
221 hook.call(object, context)
222 );
223 if (printResult === undefined) {
224 if (Array.isArray(object)) {
225 const sortedItems = [...object];
226 this._forEachLevel(this.hooks.sortItems, type, (h) =>
227 h.call(
228 sortedItems,
229 /** @type {StatsPrinterContextWithExtra} */
230 (context)
231 )
232 );
233 const printedItems = sortedItems.map((item, i) => {
234 const itemContext =
235 /** @type {StatsPrinterContextWithExtra} */
236 ({
237 ...context,
238 _index: i
239 });
240 const itemName = this._forEachLevel(
241 this.hooks.getItemName,
242 `${type}[]`,
243 (h) => h.call(item, itemContext)
244 );
245 if (itemName) itemContext[itemName] = item;
246 return this.print(
247 itemName ? `${type}[].${itemName}` : `${type}[]`,
248 item,
249 itemContext
250 );
251 });
252 printResult = this._forEachLevel(this.hooks.printItems, type, (h) =>
253 h.call(
254 /** @type {string[]} */ (printedItems),
255 /** @type {StatsPrinterContextWithExtra} */
256 (context)
257 )
258 );
259 if (printResult === undefined) {
260 const result = printedItems.filter(Boolean);
261 if (result.length > 0) printResult = result.join("\n");
262 }
263 } else if (object !== null && typeof object === "object") {
264 const elements = Object.keys(object).filter(
265 (key) => object[key] !== undefined
266 );
267 this._forEachLevel(this.hooks.sortElements, type, (h) =>
268 h.call(
269 elements,
270 /** @type {StatsPrinterContextWithExtra} */
271 (context)
272 )
273 );
274 const printedElements = elements.map((element) => {
275 const content = this.print(`${type}.${element}`, object[element], {
276 ...context,
277 _parent: object,
278 _element: element,
279 [element]: object[element]
280 });
281 return { element, content };
282 });
283 printResult = this._forEachLevel(this.hooks.printElements, type, (h) =>
284 h.call(
285 printedElements,
286 /** @type {StatsPrinterContextWithExtra} */
287 (context)
288 )
289 );
290 if (printResult === undefined) {
291 const result = printedElements.map((e) => e.content).filter(Boolean);
292 if (result.length > 0) printResult = result.join("\n");
293 }
294 }
295 }
296
297 return this._forEachLevelWaterfall(
298 this.hooks.result,
299 type,
300 /** @type {string} */
301 (printResult),
302 (h, r) => h.call(r, /** @type {StatsPrinterContextWithExtra} */ (context))
303 );
304 }
305}
306
307module.exports = StatsPrinter;
Note: See TracBrowser for help on using the repository browser.