source: frontend/node_modules/webpack/lib/stats/StatsFactory.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: 14.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");
9const { concatComparators, keepOriginalOrder } = require("../util/comparators");
10const smartGrouping = require("../util/smartGrouping");
11
12/** @typedef {import("../Chunk")} Chunk */
13/** @typedef {import("../ChunkGroup").OriginRecord} OriginRecord */
14/** @typedef {import("../Compilation")} Compilation */
15/** @typedef {import("../Compilation").Asset} Asset */
16/** @typedef {import("../Compilation").NormalizedStatsOptions} NormalizedStatsOptions */
17/** @typedef {import("../Dependency")} Dependency */
18/** @typedef {import("../Module")} Module */
19/** @typedef {import("../ModuleGraph").ModuleProfile} ModuleProfile */
20/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
21/** @typedef {import("../errors/WebpackError")} WebpackError */
22/** @typedef {import("../util/comparators").Comparator<EXPECTED_ANY>} Comparator */
23/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
24/**
25 * Defines the group config type used by this module.
26 * @template T, R
27 * @typedef {import("../util/smartGrouping").GroupConfig<T, R>} GroupConfig
28 */
29/** @typedef {import("./DefaultStatsFactoryPlugin").ChunkGroupInfoWithName} ChunkGroupInfoWithName */
30/** @typedef {import("./DefaultStatsFactoryPlugin").ModuleIssuerPath} ModuleIssuerPath */
31/** @typedef {import("./DefaultStatsFactoryPlugin").ModuleTrace} ModuleTrace */
32/** @typedef {import("./DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
33/** @typedef {import("./DefaultStatsFactoryPlugin").StatsChunk} StatsChunk */
34/** @typedef {import("./DefaultStatsFactoryPlugin").StatsChunkGroup} StatsChunkGroup */
35/** @typedef {import("./DefaultStatsFactoryPlugin").StatsChunkOrigin} StatsChunkOrigin */
36/** @typedef {import("./DefaultStatsFactoryPlugin").StatsCompilation} StatsCompilation */
37/** @typedef {import("./DefaultStatsFactoryPlugin").StatsError} StatsError */
38/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModule} StatsModule */
39/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleIssuer} StatsModuleIssuer */
40/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleReason} StatsModuleReason */
41/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleTraceDependency} StatsModuleTraceDependency */
42/** @typedef {import("./DefaultStatsFactoryPlugin").StatsModuleTraceItem} StatsModuleTraceItem */
43/** @typedef {import("./DefaultStatsFactoryPlugin").StatsProfile} StatsProfile */
44
45/**
46 * Defines the known stats factory context type used by this module.
47 * @typedef {object} KnownStatsFactoryContext
48 * @property {string} type
49 * @property {Compilation} compilation
50 * @property {(path: string) => string} makePathsRelative
51 * @property {Set<Module>} rootModules
52 * @property {Map<string, Chunk[]>} compilationFileToChunks
53 * @property {Map<string, Chunk[]>} compilationAuxiliaryFileToChunks
54 * @property {RuntimeSpec} runtime
55 * @property {(compilation: Compilation) => Error[]} cachedGetErrors
56 * @property {(compilation: Compilation) => Error[]} cachedGetWarnings
57 */
58
59/** @typedef {KnownStatsFactoryContext & Record<string, EXPECTED_ANY>} StatsFactoryContext */
60
61// StatsLogging StatsLoggingEntry
62
63/**
64 * Defines the stats object type used by this module.
65 * @template T
66 * @template F
67 * @typedef {T extends Compilation ? StatsCompilation : T extends ChunkGroupInfoWithName ? StatsChunkGroup : T extends Chunk ? StatsChunk : T extends OriginRecord ? StatsChunkOrigin : T extends Module ? StatsModule : T extends ModuleGraphConnection ? StatsModuleReason : T extends Asset ? StatsAsset : T extends ModuleTrace ? StatsModuleTraceItem : T extends Dependency ? StatsModuleTraceDependency : T extends Error ? StatsError : T extends ModuleProfile ? StatsProfile : F} StatsObject
68 */
69
70/**
71 * Defines the created object type used by this module.
72 * @template T
73 * @template F
74 * @typedef {T extends ChunkGroupInfoWithName[] ? Record<string, StatsObject<ChunkGroupInfoWithName, F>> : T extends (infer V)[] ? StatsObject<V, F>[] : StatsObject<T, F>} CreatedObject
75 */
76
77/** @typedef {EXPECTED_ANY} ObjectForExtract */
78/** @typedef {EXPECTED_ANY} FactoryData */
79/** @typedef {EXPECTED_ANY} FactoryDataItem */
80/** @typedef {EXPECTED_ANY} Result */
81
82/**
83 * Defines the stats factory hooks type used by this module.
84 * @typedef {object} StatsFactoryHooks
85 * @property {HookMap<SyncBailHook<[ObjectForExtract, FactoryData, StatsFactoryContext], void>>} extract
86 * @property {HookMap<SyncBailHook<[FactoryDataItem, StatsFactoryContext, number, number], boolean | void>>} filter
87 * @property {HookMap<SyncBailHook<[Comparator[], StatsFactoryContext], void>>} sort
88 * @property {HookMap<SyncBailHook<[FactoryDataItem, StatsFactoryContext, number, number], boolean | void>>} filterSorted
89 * @property {HookMap<SyncBailHook<[GroupConfig<EXPECTED_ANY, EXPECTED_ANY>[], StatsFactoryContext], void>>} groupResults
90 * @property {HookMap<SyncBailHook<[Comparator[], StatsFactoryContext], void>>} sortResults
91 * @property {HookMap<SyncBailHook<[FactoryDataItem, StatsFactoryContext, number, number], boolean | void>>} filterResults
92 * @property {HookMap<SyncBailHook<[FactoryDataItem[], StatsFactoryContext], Result | void>>} merge
93 * @property {HookMap<SyncBailHook<[Result, StatsFactoryContext], Result>>} result
94 * @property {HookMap<SyncBailHook<[FactoryDataItem, StatsFactoryContext], string | void>>} getItemName
95 * @property {HookMap<SyncBailHook<[FactoryDataItem, StatsFactoryContext], StatsFactory | void>>} getItemFactory
96 */
97
98/**
99 * Represents the stats factory runtime component.
100 * @template T
101 * @typedef {Map<string, T[]>} Caches
102 */
103
104class StatsFactory {
105 constructor() {
106 /** @type {StatsFactoryHooks} */
107 this.hooks = Object.freeze({
108 extract: new HookMap(
109 () => new SyncBailHook(["object", "data", "context"])
110 ),
111 filter: new HookMap(
112 () => new SyncBailHook(["item", "context", "index", "unfilteredIndex"])
113 ),
114 sort: new HookMap(() => new SyncBailHook(["comparators", "context"])),
115 filterSorted: new HookMap(
116 () => new SyncBailHook(["item", "context", "index", "unfilteredIndex"])
117 ),
118 groupResults: new HookMap(
119 () => new SyncBailHook(["groupConfigs", "context"])
120 ),
121 sortResults: new HookMap(
122 () => new SyncBailHook(["comparators", "context"])
123 ),
124 filterResults: new HookMap(
125 () => new SyncBailHook(["item", "context", "index", "unfilteredIndex"])
126 ),
127 merge: new HookMap(() => new SyncBailHook(["items", "context"])),
128 result: new HookMap(() => new SyncWaterfallHook(["result", "context"])),
129 getItemName: new HookMap(() => new SyncBailHook(["item", "context"])),
130 getItemFactory: new HookMap(() => new SyncBailHook(["item", "context"]))
131 });
132 const hooks = this.hooks;
133 this._caches =
134 /** @type {{ [Key in keyof StatsFactoryHooks]: Map<string, SyncBailHook<EXPECTED_ANY, EXPECTED_ANY>[]> }} */ ({});
135 for (const key of Object.keys(hooks)) {
136 this._caches[/** @type {keyof StatsFactoryHooks} */ (key)] = new Map();
137 }
138 this._inCreate = false;
139 }
140
141 /**
142 * Get all level hooks.
143 * @template {StatsFactoryHooks[keyof StatsFactoryHooks]} HM
144 * @template {HM extends HookMap<infer H> ? H : never} H
145 * @param {HM} hookMap hook map
146 * @param {Caches<H>} cache cache
147 * @param {string} type type
148 * @returns {H[]} hooks
149 * @private
150 */
151 _getAllLevelHooks(hookMap, cache, type) {
152 const cacheEntry = cache.get(type);
153 if (cacheEntry !== undefined) {
154 return cacheEntry;
155 }
156 const hooks = /** @type {H[]} */ ([]);
157 const typeParts = type.split(".");
158 for (let i = 0; i < typeParts.length; i++) {
159 const hook = /** @type {H} */ (hookMap.get(typeParts.slice(i).join(".")));
160 if (hook) {
161 hooks.push(hook);
162 }
163 }
164 cache.set(type, hooks);
165 return hooks;
166 }
167
168 /**
169 * Returns hook.
170 * @template {StatsFactoryHooks[keyof StatsFactoryHooks]} HM
171 * @template {HM extends HookMap<infer H> ? H : never} H
172 * @template {H extends import("tapable").Hook<EXPECTED_ANY, infer R> ? R : never} R
173 * @param {HM} hookMap hook map
174 * @param {Caches<H>} cache cache
175 * @param {string} type type
176 * @param {(hook: H) => R | void} fn fn
177 * @returns {R | void} hook
178 * @private
179 */
180 _forEachLevel(hookMap, cache, type, fn) {
181 for (const hook of this._getAllLevelHooks(hookMap, cache, type)) {
182 const result = fn(/** @type {H} */ (hook));
183 if (result !== undefined) return result;
184 }
185 }
186
187 /**
188 * For each level waterfall.
189 * @template {StatsFactoryHooks[keyof StatsFactoryHooks]} HM
190 * @template {HM extends HookMap<infer H> ? H : never} H
191 * @param {HM} hookMap hook map
192 * @param {Caches<H>} cache cache
193 * @param {string} type type
194 * @param {FactoryData} data data
195 * @param {(hook: H, factoryData: FactoryData) => FactoryData} fn fn
196 * @returns {FactoryData} data
197 * @private
198 */
199 _forEachLevelWaterfall(hookMap, cache, type, data, fn) {
200 for (const hook of this._getAllLevelHooks(hookMap, cache, type)) {
201 data = fn(/** @type {H} */ (hook), data);
202 }
203 return data;
204 }
205
206 /**
207 * For each level filter.
208 * @template {StatsFactoryHooks[keyof StatsFactoryHooks]} T
209 * @template {T extends HookMap<infer H> ? H : never} H
210 * @template {H extends import("tapable").Hook<EXPECTED_ANY, infer R> ? R : never} R
211 * @param {T} hookMap hook map
212 * @param {Caches<H>} cache cache
213 * @param {string} type type
214 * @param {FactoryData[]} items items
215 * @param {(hook: H, item: R, idx: number, i: number) => R | undefined} fn fn
216 * @param {boolean} forceClone force clone
217 * @returns {R[]} result for each level
218 * @private
219 */
220 _forEachLevelFilter(hookMap, cache, type, items, fn, forceClone) {
221 const hooks = this._getAllLevelHooks(hookMap, cache, type);
222 if (hooks.length === 0) return forceClone ? [...items] : items;
223 let i = 0;
224 return items.filter((item, idx) => {
225 for (const hook of hooks) {
226 const r = fn(/** @type {H} */ (hook), item, idx, i);
227 if (r !== undefined) {
228 if (r) i++;
229 return r;
230 }
231 }
232 i++;
233 return true;
234 });
235 }
236
237 /**
238 * Returns created object.
239 * @template FactoryData
240 * @template FallbackCreatedObject
241 * @param {string} type type
242 * @param {FactoryData} data factory data
243 * @param {Omit<StatsFactoryContext, "type">} baseContext context used as base
244 * @returns {CreatedObject<FactoryData, FallbackCreatedObject>} created object
245 */
246 create(type, data, baseContext) {
247 if (this._inCreate) {
248 return this._create(type, data, baseContext);
249 }
250 try {
251 this._inCreate = true;
252 return this._create(type, data, baseContext);
253 } finally {
254 for (const key of Object.keys(this._caches)) {
255 this._caches[/** @type {keyof StatsFactoryHooks} */ (key)].clear();
256 }
257 this._inCreate = false;
258 }
259 }
260
261 /**
262 * Returns created object.
263 * @private
264 * @template FactoryData
265 * @template FallbackCreatedObject
266 * @param {string} type type
267 * @param {FactoryData} data factory data
268 * @param {Omit<StatsFactoryContext, "type">} baseContext context used as base
269 * @returns {CreatedObject<FactoryData, FallbackCreatedObject>} created object
270 */
271 _create(type, data, baseContext) {
272 const context = /** @type {StatsFactoryContext} */ ({
273 ...baseContext,
274 type,
275 [type]: data
276 });
277 if (Array.isArray(data)) {
278 // run filter on unsorted items
279 const items = this._forEachLevelFilter(
280 this.hooks.filter,
281 this._caches.filter,
282 type,
283 data,
284 (h, r, idx, i) => h.call(r, context, idx, i),
285 true
286 );
287
288 // sort items
289 /** @type {Comparator[]} */
290 const comparators = [];
291 this._forEachLevel(this.hooks.sort, this._caches.sort, type, (h) =>
292 h.call(comparators, context)
293 );
294 if (comparators.length > 0) {
295 items.sort(
296 // @ts-expect-error number of arguments is correct
297 concatComparators(...comparators, keepOriginalOrder(items))
298 );
299 }
300
301 // run filter on sorted items
302 const items2 = this._forEachLevelFilter(
303 this.hooks.filterSorted,
304 this._caches.filterSorted,
305 type,
306 items,
307 (h, r, idx, i) => h.call(r, context, idx, i),
308 false
309 );
310
311 // for each item
312 let resultItems = items2.map((item, i) => {
313 /** @type {StatsFactoryContext} */
314 const itemContext = {
315 ...context,
316 _index: i
317 };
318
319 // run getItemName
320 const itemName = this._forEachLevel(
321 this.hooks.getItemName,
322 this._caches.getItemName,
323 `${type}[]`,
324 (h) => h.call(item, itemContext)
325 );
326 if (itemName) itemContext[itemName] = item;
327 const innerType = itemName ? `${type}[].${itemName}` : `${type}[]`;
328
329 // run getItemFactory
330 const itemFactory =
331 this._forEachLevel(
332 this.hooks.getItemFactory,
333 this._caches.getItemFactory,
334 innerType,
335 (h) => h.call(item, itemContext)
336 ) || this;
337
338 // run item factory
339 return itemFactory.create(innerType, item, itemContext);
340 });
341
342 // sort result items
343 /** @type {Comparator[]} */
344 const comparators2 = [];
345 this._forEachLevel(
346 this.hooks.sortResults,
347 this._caches.sortResults,
348 type,
349 (h) => h.call(comparators2, context)
350 );
351 if (comparators2.length > 0) {
352 resultItems.sort(
353 // @ts-expect-error number of arguments is correct
354 concatComparators(...comparators2, keepOriginalOrder(resultItems))
355 );
356 }
357
358 // group result items
359 /** @type {GroupConfig<EXPECTED_ANY, EXPECTED_ANY>[]} */
360 const groupConfigs = [];
361 this._forEachLevel(
362 this.hooks.groupResults,
363 this._caches.groupResults,
364 type,
365 (h) => h.call(groupConfigs, context)
366 );
367 if (groupConfigs.length > 0) {
368 resultItems = smartGrouping(resultItems, groupConfigs);
369 }
370
371 // run filter on sorted result items
372 const finalResultItems = this._forEachLevelFilter(
373 this.hooks.filterResults,
374 this._caches.filterResults,
375 type,
376 resultItems,
377 (h, r, idx, i) => h.call(r, context, idx, i),
378 false
379 );
380
381 // run merge on mapped items
382 let result = this._forEachLevel(
383 this.hooks.merge,
384 this._caches.merge,
385 type,
386 (h) => h.call(finalResultItems, context)
387 );
388 if (result === undefined) result = finalResultItems;
389
390 // run result on merged items
391 return this._forEachLevelWaterfall(
392 this.hooks.result,
393 this._caches.result,
394 type,
395 result,
396 (h, r) => h.call(r, context)
397 );
398 }
399 /** @type {ObjectForExtract} */
400 const object = {};
401
402 // run extract on value
403 this._forEachLevel(this.hooks.extract, this._caches.extract, type, (h) =>
404 h.call(object, data, context)
405 );
406
407 // run result on extracted object
408 return this._forEachLevelWaterfall(
409 this.hooks.result,
410 this._caches.result,
411 type,
412 object,
413 (h, r) => h.call(r, context)
414 );
415 }
416}
417
418module.exports = StatsFactory;
Note: See TracBrowser for help on using the repository browser.