| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { HookMap, SyncBailHook, SyncWaterfallHook } = require("tapable"); | 
					
						
							|  |  |  | const { concatComparators, keepOriginalOrder } = require("../util/comparators"); | 
					
						
							| 
									
										
										
										
											2020-08-27 15:59:12 +08:00
										 |  |  | const smartGrouping = require("../util/smartGrouping"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | /** @typedef {import("../Chunk")} Chunk */ | 
					
						
							|  |  |  | /** @typedef {import("../Compilation")} Compilation */ | 
					
						
							|  |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							|  |  |  | /** @typedef {import("../WebpackError")} WebpackError */ | 
					
						
							|  |  |  | /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-27 15:59:12 +08:00
										 |  |  | /** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} KnownStatsFactoryContext | 
					
						
							|  |  |  |  * @property {string} type | 
					
						
							|  |  |  |  * @property {function(string): string=} makePathsRelative | 
					
						
							|  |  |  |  * @property {Compilation=} compilation | 
					
						
							|  |  |  |  * @property {Set<Module>=} rootModules | 
					
						
							|  |  |  |  * @property {Map<string,Chunk[]>=} compilationFileToChunks | 
					
						
							|  |  |  |  * @property {Map<string,Chunk[]>=} compilationAuxiliaryFileToChunks | 
					
						
							|  |  |  |  * @property {RuntimeSpec=} runtime | 
					
						
							|  |  |  |  * @property {function(Compilation): WebpackError[]=} cachedGetErrors | 
					
						
							|  |  |  |  * @property {function(Compilation): WebpackError[]=} cachedGetWarnings | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {KnownStatsFactoryContext & Record<string, any>} StatsFactoryContext */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | class StatsFactory { | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							|  |  |  | 		this.hooks = Object.freeze({ | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[Object, any, StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			extract: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["object", "data", "context"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any, StatsFactoryContext, number, number]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			filter: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["item", "context", "index", "unfilteredIndex"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[(function(any, any): number)[], StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			sort: new HookMap(() => new SyncBailHook(["comparators", "context"])), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any, StatsFactoryContext, number, number]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			filterSorted: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["item", "context", "index", "unfilteredIndex"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[GroupConfig[], StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2020-08-27 15:59:12 +08:00
										 |  |  | 			groupResults: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["groupConfigs", "context"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[(function(any, any): number)[], StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			sortResults: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["comparators", "context"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any, StatsFactoryContext, number, number]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			filterResults: new HookMap( | 
					
						
							|  |  |  | 				() => new SyncBailHook(["item", "context", "index", "unfilteredIndex"]) | 
					
						
							|  |  |  | 			), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any[], StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			merge: new HookMap(() => new SyncBailHook(["items", "context"])), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any[], StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			result: new HookMap(() => new SyncWaterfallHook(["result", "context"])), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any, StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			getItemName: new HookMap(() => new SyncBailHook(["item", "context"])), | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 			/** @type {HookMap<SyncBailHook<[any, StatsFactoryContext]>>} */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			getItemFactory: new HookMap(() => new SyncBailHook(["item", "context"])) | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 		const hooks = this.hooks; | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | 		this._caches = | 
					
						
							|  |  |  | 			/** @type {Record<keyof typeof hooks, Map<string, SyncBailHook<[any[], StatsFactoryContext]>[]>>} */ ({}); | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 		for (const key of Object.keys(hooks)) { | 
					
						
							|  |  |  | 			this._caches[key] = new Map(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 		this._inCreate = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 	_getAllLevelHooks(hookMap, cache, type) { | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 		const cacheEntry = cache.get(type); | 
					
						
							|  |  |  | 		if (cacheEntry !== undefined) { | 
					
						
							|  |  |  | 			return cacheEntry; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		const hooks = []; | 
					
						
							|  |  |  | 		const typeParts = type.split("."); | 
					
						
							|  |  |  | 		for (let i = 0; i < typeParts.length; i++) { | 
					
						
							|  |  |  | 			const hook = hookMap.get(typeParts.slice(i).join(".")); | 
					
						
							|  |  |  | 			if (hook) { | 
					
						
							|  |  |  | 				hooks.push(hook); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cache.set(type, hooks); | 
					
						
							|  |  |  | 		return hooks; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 	_forEachLevel(hookMap, cache, type, fn) { | 
					
						
							|  |  |  | 		for (const hook of this._getAllLevelHooks(hookMap, cache, type)) { | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			const result = fn(hook); | 
					
						
							|  |  |  | 			if (result !== undefined) return result; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 	_forEachLevelWaterfall(hookMap, cache, type, data, fn) { | 
					
						
							|  |  |  | 		for (const hook of this._getAllLevelHooks(hookMap, cache, type)) { | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			data = fn(hook, data); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return data; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 	_forEachLevelFilter(hookMap, cache, type, items, fn, forceClone) { | 
					
						
							|  |  |  | 		const hooks = this._getAllLevelHooks(hookMap, cache, type); | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 		if (hooks.length === 0) return forceClone ? items.slice() : items; | 
					
						
							|  |  |  | 		let i = 0; | 
					
						
							|  |  |  | 		return items.filter((item, idx) => { | 
					
						
							|  |  |  | 			for (const hook of hooks) { | 
					
						
							|  |  |  | 				const r = fn(hook, item, idx, i); | 
					
						
							|  |  |  | 				if (r !== undefined) { | 
					
						
							|  |  |  | 					if (r) i++; | 
					
						
							|  |  |  | 					return r; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			i++; | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 01:51:55 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} type type | 
					
						
							|  |  |  | 	 * @param {any} data factory data | 
					
						
							|  |  |  | 	 * @param {Omit<StatsFactoryContext, "type">} baseContext context used as base | 
					
						
							|  |  |  | 	 * @returns {any} created object | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 	create(type, data, baseContext) { | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 		if (this._inCreate) { | 
					
						
							|  |  |  | 			return this._create(type, data, baseContext); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				this._inCreate = true; | 
					
						
							|  |  |  | 				return this._create(type, data, baseContext); | 
					
						
							|  |  |  | 			} finally { | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				for (const key of Object.keys(this._caches)) this._caches[key].clear(); | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 				this._inCreate = false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_create(type, data, baseContext) { | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 		const context = { | 
					
						
							|  |  |  | 			...baseContext, | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			type, | 
					
						
							|  |  |  | 			[type]: data | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 		if (Array.isArray(data)) { | 
					
						
							|  |  |  | 			// run filter on unsorted items
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			const items = this._forEachLevelFilter( | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				this.hooks.filter, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				this._caches.filter, | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				type, | 
					
						
							|  |  |  | 				data, | 
					
						
							|  |  |  | 				(h, r, idx, i) => h.call(r, context, idx, i), | 
					
						
							|  |  |  | 				true | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// sort items
 | 
					
						
							|  |  |  | 			const comparators = []; | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 			this._forEachLevel(this.hooks.sort, this._caches.sort, type, h => | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 				h.call(comparators, context) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			if (comparators.length > 0) { | 
					
						
							|  |  |  | 				items.sort( | 
					
						
							| 
									
										
										
										
											2020-03-30 23:56:37 +08:00
										 |  |  | 					// @ts-expect-error number of arguments is correct
 | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 					concatComparators(...comparators, keepOriginalOrder(items)) | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// run filter on sorted items
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			const items2 = this._forEachLevelFilter( | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				this.hooks.filterSorted, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				this._caches.filterSorted, | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				type, | 
					
						
							|  |  |  | 				items, | 
					
						
							|  |  |  | 				(h, r, idx, i) => h.call(r, context, idx, i), | 
					
						
							|  |  |  | 				false | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// for each item
 | 
					
						
							| 
									
										
										
										
											2020-08-27 15:59:12 +08:00
										 |  |  | 			let resultItems = items2.map((item, i) => { | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 				const itemContext = { | 
					
						
							|  |  |  | 					...context, | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 					_index: i | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// run getItemName
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 				const itemName = this._forEachLevel( | 
					
						
							|  |  |  | 					this.hooks.getItemName, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 					this._caches.getItemName, | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 					`${type}[]`, | 
					
						
							|  |  |  | 					h => h.call(item, itemContext) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 				if (itemName) itemContext[itemName] = item; | 
					
						
							|  |  |  | 				const innerType = itemName ? `${type}[].${itemName}` : `${type}[]`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// run getItemFactory
 | 
					
						
							|  |  |  | 				const itemFactory = | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 					this._forEachLevel( | 
					
						
							|  |  |  | 						this.hooks.getItemFactory, | 
					
						
							|  |  |  | 						this._caches.getItemFactory, | 
					
						
							|  |  |  | 						innerType, | 
					
						
							|  |  |  | 						h => h.call(item, itemContext) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 					) || this; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// run item factory
 | 
					
						
							|  |  |  | 				return itemFactory.create(innerType, item, itemContext); | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// sort result items
 | 
					
						
							|  |  |  | 			const comparators2 = []; | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 			this._forEachLevel( | 
					
						
							|  |  |  | 				this.hooks.sortResults, | 
					
						
							|  |  |  | 				this._caches.sortResults, | 
					
						
							|  |  |  | 				type, | 
					
						
							|  |  |  | 				h => h.call(comparators2, context) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 			if (comparators2.length > 0) { | 
					
						
							|  |  |  | 				resultItems.sort( | 
					
						
							| 
									
										
										
										
											2020-03-30 23:56:37 +08:00
										 |  |  | 					// @ts-expect-error number of arguments is correct
 | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 					concatComparators(...comparators2, keepOriginalOrder(resultItems)) | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-02 00:08:09 +08:00
										 |  |  | 			// group result items
 | 
					
						
							|  |  |  | 			const groupConfigs = []; | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 			this._forEachLevel( | 
					
						
							|  |  |  | 				this.hooks.groupResults, | 
					
						
							|  |  |  | 				this._caches.groupResults, | 
					
						
							|  |  |  | 				type, | 
					
						
							|  |  |  | 				h => h.call(groupConfigs, context) | 
					
						
							| 
									
										
										
										
											2020-09-02 00:08:09 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 			if (groupConfigs.length > 0) { | 
					
						
							|  |  |  | 				resultItems = smartGrouping(resultItems, groupConfigs); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			// run filter on sorted result items
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			const finalResultItems = this._forEachLevelFilter( | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				this.hooks.filterResults, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				this._caches.filterResults, | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				type, | 
					
						
							|  |  |  | 				resultItems, | 
					
						
							|  |  |  | 				(h, r, idx, i) => h.call(r, context, idx, i), | 
					
						
							|  |  |  | 				false | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// run merge on mapped items
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 			let result = this._forEachLevel( | 
					
						
							|  |  |  | 				this.hooks.merge, | 
					
						
							|  |  |  | 				this._caches.merge, | 
					
						
							|  |  |  | 				type, | 
					
						
							|  |  |  | 				h => h.call(finalResultItems, context) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 			if (result === undefined) result = finalResultItems; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// run result on merged items
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			return this._forEachLevelWaterfall( | 
					
						
							|  |  |  | 				this.hooks.result, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				this._caches.result, | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 				type, | 
					
						
							|  |  |  | 				result, | 
					
						
							|  |  |  | 				(h, r) => h.call(r, context) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			const object = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// run extract on value
 | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 			this._forEachLevel(this.hooks.extract, this._caches.extract, type, h => | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 				h.call(object, data, context) | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// run result on extracted object
 | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 			return this._forEachLevelWaterfall( | 
					
						
							|  |  |  | 				this.hooks.result, | 
					
						
							| 
									
										
										
										
											2020-12-04 22:02:06 +08:00
										 |  |  | 				this._caches.result, | 
					
						
							| 
									
										
										
										
											2019-07-25 04:42:05 +08:00
										 |  |  | 				type, | 
					
						
							|  |  |  | 				object, | 
					
						
							|  |  |  | 				(h, r) => h.call(r, context) | 
					
						
							| 
									
										
										
										
											2018-12-19 01:29:12 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = StatsFactory; |