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

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

F4 Finalna Verzija

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