DefaultStatsFactoryPlugin.js 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const util = require("util");
  7. const { WEBPACK_MODULE_TYPE_RUNTIME } = require("../ModuleTypeConstants");
  8. const ModuleDependency = require("../dependencies/ModuleDependency");
  9. const formatLocation = require("../formatLocation");
  10. const { LogType } = require("../logging/Logger");
  11. const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
  12. const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin");
  13. const { countIterable } = require("../util/IterableHelpers");
  14. const {
  15. compareLocations,
  16. compareChunksById,
  17. compareNumbers,
  18. compareIds,
  19. concatComparators,
  20. compareSelect,
  21. compareModulesByIdentifier
  22. } = require("../util/comparators");
  23. const { makePathsRelative, parseResource } = require("../util/identifier");
  24. /** @typedef {import("webpack-sources").Source} Source */
  25. /** @typedef {import("../Chunk")} Chunk */
  26. /** @typedef {import("../Chunk").ChunkId} ChunkId */
  27. /** @typedef {import("../ChunkGraph").ModuleId} ModuleId */
  28. /** @typedef {import("../ChunkGroup")} ChunkGroup */
  29. /** @typedef {import("../ChunkGroup").OriginRecord} OriginRecord */
  30. /** @typedef {import("../Compilation")} Compilation */
  31. /** @typedef {import("../Compilation").Asset} Asset */
  32. /** @typedef {import("../Compilation").AssetInfo} AssetInfo */
  33. /** @typedef {import("../Compilation").KnownNormalizedStatsOptions} KnownNormalizedStatsOptions */
  34. /** @typedef {import("../Compilation").NormalizedStatsOptions} NormalizedStatsOptions */
  35. /** @typedef {import("../Compiler")} Compiler */
  36. /** @typedef {import("../Dependency")} Dependency */
  37. /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
  38. /** @typedef {import("../Module")} Module */
  39. /** @typedef {import("../Module").BuildInfo} BuildInfo */
  40. /** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
  41. /** @typedef {import("../ModuleProfile")} ModuleProfile */
  42. /** @typedef {import("../RequestShortener")} RequestShortener */
  43. /** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
  44. /** @typedef {import("../WebpackError")} WebpackError */
  45. /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
  46. /** @typedef {import("./StatsFactory")} StatsFactory */
  47. /** @typedef {import("./StatsFactory").StatsFactoryContext} StatsFactoryContext */
  48. /**
  49. * @template T
  50. * @typedef {import("../util/comparators").Comparator<T>} Comparator<T>
  51. */
  52. /**
  53. * @template T, R
  54. * @typedef {import("../util/smartGrouping").GroupConfig<T, R>} GroupConfig
  55. */
  56. /** @typedef {KnownStatsCompilation & Record<string, EXPECTED_ANY>} StatsCompilation */
  57. /**
  58. * @typedef {object} KnownStatsCompilation
  59. * @property {any=} env
  60. * @property {string=} name
  61. * @property {string=} hash
  62. * @property {string=} version
  63. * @property {number=} time
  64. * @property {number=} builtAt
  65. * @property {boolean=} needAdditionalPass
  66. * @property {string=} publicPath
  67. * @property {string=} outputPath
  68. * @property {Record<string, string[]>=} assetsByChunkName
  69. * @property {StatsAsset[]=} assets
  70. * @property {number=} filteredAssets
  71. * @property {StatsChunk[]=} chunks
  72. * @property {StatsModule[]=} modules
  73. * @property {number=} filteredModules
  74. * @property {Record<string, StatsChunkGroup>=} entrypoints
  75. * @property {Record<string, StatsChunkGroup>=} namedChunkGroups
  76. * @property {StatsError[]=} errors
  77. * @property {number=} errorsCount
  78. * @property {StatsError[]=} warnings
  79. * @property {number=} warningsCount
  80. * @property {StatsCompilation[]=} children
  81. * @property {Record<string, StatsLogging>=} logging
  82. */
  83. /** @typedef {KnownStatsLogging & Record<string, EXPECTED_ANY>} StatsLogging */
  84. /**
  85. * @typedef {object} KnownStatsLogging
  86. * @property {StatsLoggingEntry[]} entries
  87. * @property {number} filteredEntries
  88. * @property {boolean} debug
  89. */
  90. /** @typedef {KnownStatsLoggingEntry & Record<string, EXPECTED_ANY>} StatsLoggingEntry */
  91. /**
  92. * @typedef {object} KnownStatsLoggingEntry
  93. * @property {string} type
  94. * @property {string=} message
  95. * @property {string[]=} trace
  96. * @property {StatsLoggingEntry[]=} children
  97. * @property {EXPECTED_ANY[]=} args
  98. * @property {number=} time
  99. */
  100. /** @typedef {KnownStatsAsset & Record<string, EXPECTED_ANY>} StatsAsset */
  101. /**
  102. * @typedef {object} KnownStatsAsset
  103. * @property {string} type
  104. * @property {string} name
  105. * @property {AssetInfo} info
  106. * @property {number} size
  107. * @property {boolean} emitted
  108. * @property {boolean} comparedForEmit
  109. * @property {boolean} cached
  110. * @property {StatsAsset[]=} related
  111. * @property {(string|number)[]=} chunkNames
  112. * @property {(string|number)[]=} chunkIdHints
  113. * @property {(string|number)[]=} chunks
  114. * @property {(string|number)[]=} auxiliaryChunkNames
  115. * @property {(string|number)[]=} auxiliaryChunks
  116. * @property {(string|number)[]=} auxiliaryChunkIdHints
  117. * @property {number=} filteredRelated
  118. * @property {boolean=} isOverSizeLimit
  119. */
  120. /** @typedef {KnownStatsChunkGroup & Record<string, EXPECTED_ANY>} StatsChunkGroup */
  121. /**
  122. * @typedef {object} KnownStatsChunkGroup
  123. * @property {(string | null)=} name
  124. * @property {(string | number)[]=} chunks
  125. * @property {({ name: string, size?: number })[]=} assets
  126. * @property {number=} filteredAssets
  127. * @property {number=} assetsSize
  128. * @property {({ name: string, size?: number })[]=} auxiliaryAssets
  129. * @property {number=} filteredAuxiliaryAssets
  130. * @property {number=} auxiliaryAssetsSize
  131. * @property {{ [x: string]: StatsChunkGroup[] }=} children
  132. * @property {{ [x: string]: string[] }=} childAssets
  133. * @property {boolean=} isOverSizeLimit
  134. */
  135. /** @typedef {KnownStatsModule & Record<string, EXPECTED_ANY>} StatsModule */
  136. /**
  137. * @typedef {object} KnownStatsModule
  138. * @property {string=} type
  139. * @property {string=} moduleType
  140. * @property {(string | null)=} layer
  141. * @property {string=} identifier
  142. * @property {string=} name
  143. * @property {(string | null)=} nameForCondition
  144. * @property {number=} index
  145. * @property {number=} preOrderIndex
  146. * @property {number=} index2
  147. * @property {number=} postOrderIndex
  148. * @property {number=} size
  149. * @property {{ [x: string]: number }=} sizes
  150. * @property {boolean=} cacheable
  151. * @property {boolean=} built
  152. * @property {boolean=} codeGenerated
  153. * @property {boolean=} buildTimeExecuted
  154. * @property {boolean=} cached
  155. * @property {boolean=} optional
  156. * @property {boolean=} orphan
  157. * @property {string | number=} id
  158. * @property {string | number | null=} issuerId
  159. * @property {(string | number)[]=} chunks
  160. * @property {(string | number)[]=} assets
  161. * @property {boolean=} dependent
  162. * @property {(string | null)=} issuer
  163. * @property {(string | null)=} issuerName
  164. * @property {StatsModuleIssuer[]=} issuerPath
  165. * @property {boolean=} failed
  166. * @property {number=} errors
  167. * @property {number=} warnings
  168. * @property {StatsProfile=} profile
  169. * @property {StatsModuleReason[]=} reasons
  170. * @property {(boolean | null | string[])=} usedExports
  171. * @property {(string[] | null)=} providedExports
  172. * @property {string[]=} optimizationBailout
  173. * @property {(number | null)=} depth
  174. * @property {StatsModule[]=} modules
  175. * @property {number=} filteredModules
  176. * @property {ReturnType<Source["source"]>=} source
  177. */
  178. /** @typedef {KnownStatsProfile & Record<string, EXPECTED_ANY>} StatsProfile */
  179. /**
  180. * @typedef {object} KnownStatsProfile
  181. * @property {number} total
  182. * @property {number} resolving
  183. * @property {number} restoring
  184. * @property {number} building
  185. * @property {number} integration
  186. * @property {number} storing
  187. * @property {number} additionalResolving
  188. * @property {number} additionalIntegration
  189. * @property {number} factory
  190. * @property {number} dependencies
  191. */
  192. /** @typedef {KnownStatsModuleIssuer & Record<string, EXPECTED_ANY>} StatsModuleIssuer */
  193. /**
  194. * @typedef {object} KnownStatsModuleIssuer
  195. * @property {string} identifier
  196. * @property {string} name
  197. * @property {(string|number)=} id
  198. * @property {StatsProfile} profile
  199. */
  200. /** @typedef {KnownStatsModuleReason & Record<string, EXPECTED_ANY>} StatsModuleReason */
  201. /**
  202. * @typedef {object} KnownStatsModuleReason
  203. * @property {string | null} moduleIdentifier
  204. * @property {string | null} module
  205. * @property {string | null} moduleName
  206. * @property {string | null} resolvedModuleIdentifier
  207. * @property {string | null} resolvedModule
  208. * @property {string | null} type
  209. * @property {boolean} active
  210. * @property {string | null} explanation
  211. * @property {string | null} userRequest
  212. * @property {(string | null)=} loc
  213. * @property {(string | number | null)=} moduleId
  214. * @property {(string | number | null)=} resolvedModuleId
  215. */
  216. /** @typedef {KnownStatsChunk & Record<string, EXPECTED_ANY>} StatsChunk */
  217. /**
  218. * @typedef {object} KnownStatsChunk
  219. * @property {boolean} rendered
  220. * @property {boolean} initial
  221. * @property {boolean} entry
  222. * @property {boolean} recorded
  223. * @property {string=} reason
  224. * @property {number} size
  225. * @property {Record<string, number>} sizes
  226. * @property {string[]} names
  227. * @property {string[]} idHints
  228. * @property {string[]=} runtime
  229. * @property {string[]} files
  230. * @property {string[]} auxiliaryFiles
  231. * @property {string} hash
  232. * @property {Record<string, (string|number)[]>} childrenByOrder
  233. * @property {(string|number)=} id
  234. * @property {(string|number)[]=} siblings
  235. * @property {(string|number)[]=} parents
  236. * @property {(string|number)[]=} children
  237. * @property {StatsModule[]=} modules
  238. * @property {number=} filteredModules
  239. * @property {StatsChunkOrigin[]=} origins
  240. */
  241. /** @typedef {KnownStatsChunkOrigin & Record<string, EXPECTED_ANY>} StatsChunkOrigin */
  242. /**
  243. * @typedef {object} KnownStatsChunkOrigin
  244. * @property {string} module
  245. * @property {string} moduleIdentifier
  246. * @property {string} moduleName
  247. * @property {string} loc
  248. * @property {string} request
  249. * @property {(string | number)=} moduleId
  250. */
  251. /** @typedef {KnownStatsModuleTraceItem & Record<string, EXPECTED_ANY>} StatsModuleTraceItem */
  252. /**
  253. * @typedef {object} KnownStatsModuleTraceItem
  254. * @property {string=} originIdentifier
  255. * @property {string=} originName
  256. * @property {string=} moduleIdentifier
  257. * @property {string=} moduleName
  258. * @property {StatsModuleTraceDependency[]=} dependencies
  259. * @property {(string|number)=} originId
  260. * @property {(string|number)=} moduleId
  261. */
  262. /** @typedef {KnownStatsModuleTraceDependency & Record<string, EXPECTED_ANY>} StatsModuleTraceDependency */
  263. /**
  264. * @typedef {object} KnownStatsModuleTraceDependency
  265. * @property {string=} loc
  266. */
  267. /** @typedef {KnownStatsError & Record<string, EXPECTED_ANY>} StatsError */
  268. /**
  269. * @typedef {object} KnownStatsError
  270. * @property {string} message
  271. * @property {string=} chunkName
  272. * @property {boolean=} chunkEntry
  273. * @property {boolean=} chunkInitial
  274. * @property {string=} file
  275. * @property {string=} moduleIdentifier
  276. * @property {string=} moduleName
  277. * @property {string=} loc
  278. * @property {ChunkId=} chunkId
  279. * @property {string|number=} moduleId
  280. * @property {StatsModuleTraceItem[]=} moduleTrace
  281. * @property {string=} details
  282. * @property {string=} stack
  283. * @property {string=} compilerPath
  284. */
  285. /** @typedef {Asset & { type: string, related: PreprocessedAsset[] | undefined }} PreprocessedAsset */
  286. /**
  287. * @template T
  288. * @template O
  289. * @typedef {Record<string, (object: O, data: T, context: StatsFactoryContext, options: NormalizedStatsOptions, factory: StatsFactory) => void>} ExtractorsByOption
  290. */
  291. /**
  292. * @typedef {object} SimpleExtractors
  293. * @property {ExtractorsByOption<Compilation, StatsCompilation>} compilation
  294. * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset
  295. * @property {ExtractorsByOption<PreprocessedAsset, StatsAsset>} asset$visible
  296. * @property {ExtractorsByOption<{ name: string, chunkGroup: ChunkGroup }, StatsChunkGroup>} chunkGroup
  297. * @property {ExtractorsByOption<Module, StatsModule>} module
  298. * @property {ExtractorsByOption<Module, StatsModule>} module$visible
  299. * @property {ExtractorsByOption<Module, StatsModuleIssuer>} moduleIssuer
  300. * @property {ExtractorsByOption<ModuleProfile, StatsProfile>} profile
  301. * @property {ExtractorsByOption<ModuleGraphConnection, StatsModuleReason>} moduleReason
  302. * @property {ExtractorsByOption<Chunk, StatsChunk>} chunk
  303. * @property {ExtractorsByOption<OriginRecord, StatsChunkOrigin>} chunkOrigin
  304. * @property {ExtractorsByOption<WebpackError, StatsError>} error
  305. * @property {ExtractorsByOption<WebpackError, StatsError>} warning
  306. * @property {ExtractorsByOption<{ origin: Module, module: Module }, StatsModuleTraceItem>} moduleTraceItem
  307. * @property {ExtractorsByOption<Dependency, StatsModuleTraceDependency>} moduleTraceDependency
  308. */
  309. /**
  310. * @template T
  311. * @template I
  312. * @param {Iterable<T>} items items to select from
  313. * @param {(item: T) => Iterable<I>} selector selector function to select values from item
  314. * @returns {I[]} array of values
  315. */
  316. const uniqueArray = (items, selector) => {
  317. /** @type {Set<I>} */
  318. const set = new Set();
  319. for (const item of items) {
  320. for (const i of selector(item)) {
  321. set.add(i);
  322. }
  323. }
  324. return Array.from(set);
  325. };
  326. /**
  327. * @template T
  328. * @template I
  329. * @param {Iterable<T>} items items to select from
  330. * @param {(item: T) => Iterable<I>} selector selector function to select values from item
  331. * @param {Comparator<I>} comparator comparator function
  332. * @returns {I[]} array of values
  333. */
  334. const uniqueOrderedArray = (items, selector, comparator) =>
  335. uniqueArray(items, selector).sort(comparator);
  336. /** @template T @template R @typedef {{ [P in keyof T]: R }} MappedValues<T, R> */
  337. /**
  338. * @template {object} T
  339. * @template {object} R
  340. * @param {T} obj object to be mapped
  341. * @param {function(T[keyof T], keyof T): R} fn mapping function
  342. * @returns {MappedValues<T, R>} mapped object
  343. */
  344. const mapObject = (obj, fn) => {
  345. const newObj = Object.create(null);
  346. for (const key of Object.keys(obj)) {
  347. newObj[key] = fn(
  348. obj[/** @type {keyof T} */ (key)],
  349. /** @type {keyof T} */ (key)
  350. );
  351. }
  352. return newObj;
  353. };
  354. /**
  355. * @template T
  356. * @param {Compilation} compilation the compilation
  357. * @param {(compilation: Compilation, name: string) => T[]} getItems get items
  358. * @returns {number} total number
  359. */
  360. const countWithChildren = (compilation, getItems) => {
  361. let count = getItems(compilation, "").length;
  362. for (const child of compilation.children) {
  363. count += countWithChildren(child, (c, type) =>
  364. getItems(c, `.children[].compilation${type}`)
  365. );
  366. }
  367. return count;
  368. };
  369. /** @type {ExtractorsByOption<WebpackError | string, StatsError>} */
  370. const EXTRACT_ERROR = {
  371. _: (object, error, context, { requestShortener }) => {
  372. // TODO webpack 6 disallow strings in the errors/warnings list
  373. if (typeof error === "string") {
  374. object.message = error;
  375. } else {
  376. if (error.chunk) {
  377. object.chunkName =
  378. /** @type {string | undefined} */
  379. (error.chunk.name);
  380. object.chunkEntry = error.chunk.hasRuntime();
  381. object.chunkInitial = error.chunk.canBeInitial();
  382. }
  383. if (error.file) {
  384. object.file = error.file;
  385. }
  386. if (error.module) {
  387. object.moduleIdentifier = error.module.identifier();
  388. object.moduleName = error.module.readableIdentifier(requestShortener);
  389. }
  390. if (error.loc) {
  391. object.loc = formatLocation(error.loc);
  392. }
  393. object.message = error.message;
  394. }
  395. },
  396. ids: (object, error, { compilation: { chunkGraph } }) => {
  397. if (typeof error !== "string") {
  398. if (error.chunk) {
  399. object.chunkId = /** @type {ChunkId} */ (error.chunk.id);
  400. }
  401. if (error.module) {
  402. object.moduleId =
  403. /** @type {ModuleId} */
  404. (chunkGraph.getModuleId(error.module));
  405. }
  406. }
  407. },
  408. moduleTrace: (object, error, context, options, factory) => {
  409. if (typeof error !== "string" && error.module) {
  410. const {
  411. type,
  412. compilation: { moduleGraph }
  413. } = context;
  414. /** @type {Set<Module>} */
  415. const visitedModules = new Set();
  416. const moduleTrace = [];
  417. let current = error.module;
  418. while (current) {
  419. if (visitedModules.has(current)) break; // circular (technically impossible, but how knows)
  420. visitedModules.add(current);
  421. const origin = moduleGraph.getIssuer(current);
  422. if (!origin) break;
  423. moduleTrace.push({ origin, module: current });
  424. current = origin;
  425. }
  426. object.moduleTrace = factory.create(
  427. `${type}.moduleTrace`,
  428. moduleTrace,
  429. context
  430. );
  431. }
  432. },
  433. errorDetails: (
  434. object,
  435. error,
  436. { type, compilation, cachedGetErrors, cachedGetWarnings },
  437. { errorDetails }
  438. ) => {
  439. if (
  440. typeof error !== "string" &&
  441. (errorDetails === true ||
  442. (type.endsWith(".error") && cachedGetErrors(compilation).length < 3))
  443. ) {
  444. object.details = error.details;
  445. }
  446. },
  447. errorStack: (object, error) => {
  448. if (typeof error !== "string") {
  449. object.stack = error.stack;
  450. }
  451. }
  452. };
  453. /** @type {SimpleExtractors} */
  454. const SIMPLE_EXTRACTORS = {
  455. compilation: {
  456. _: (object, compilation, context, options) => {
  457. if (!context.makePathsRelative) {
  458. context.makePathsRelative = makePathsRelative.bindContextCache(
  459. compilation.compiler.context,
  460. compilation.compiler.root
  461. );
  462. }
  463. if (!context.cachedGetErrors) {
  464. const map = new WeakMap();
  465. context.cachedGetErrors = compilation =>
  466. map.get(compilation) ||
  467. // eslint-disable-next-line no-sequences
  468. (errors => (map.set(compilation, errors), errors))(
  469. compilation.getErrors()
  470. );
  471. }
  472. if (!context.cachedGetWarnings) {
  473. const map = new WeakMap();
  474. context.cachedGetWarnings = compilation =>
  475. map.get(compilation) ||
  476. // eslint-disable-next-line no-sequences
  477. (warnings => (map.set(compilation, warnings), warnings))(
  478. compilation.getWarnings()
  479. );
  480. }
  481. if (compilation.name) {
  482. object.name = compilation.name;
  483. }
  484. if (compilation.needAdditionalPass) {
  485. object.needAdditionalPass = true;
  486. }
  487. const { logging, loggingDebug, loggingTrace } = options;
  488. if (logging || (loggingDebug && loggingDebug.length > 0)) {
  489. const util = require("util");
  490. object.logging = {};
  491. let acceptedTypes;
  492. let collapsedGroups = false;
  493. switch (logging) {
  494. case "error":
  495. acceptedTypes = new Set([LogType.error]);
  496. break;
  497. case "warn":
  498. acceptedTypes = new Set([LogType.error, LogType.warn]);
  499. break;
  500. case "info":
  501. acceptedTypes = new Set([
  502. LogType.error,
  503. LogType.warn,
  504. LogType.info
  505. ]);
  506. break;
  507. case "log":
  508. acceptedTypes = new Set([
  509. LogType.error,
  510. LogType.warn,
  511. LogType.info,
  512. LogType.log,
  513. LogType.group,
  514. LogType.groupEnd,
  515. LogType.groupCollapsed,
  516. LogType.clear
  517. ]);
  518. break;
  519. case "verbose":
  520. acceptedTypes = new Set([
  521. LogType.error,
  522. LogType.warn,
  523. LogType.info,
  524. LogType.log,
  525. LogType.group,
  526. LogType.groupEnd,
  527. LogType.groupCollapsed,
  528. LogType.profile,
  529. LogType.profileEnd,
  530. LogType.time,
  531. LogType.status,
  532. LogType.clear
  533. ]);
  534. collapsedGroups = true;
  535. break;
  536. default:
  537. acceptedTypes = new Set();
  538. break;
  539. }
  540. const cachedMakePathsRelative = makePathsRelative.bindContextCache(
  541. options.context,
  542. compilation.compiler.root
  543. );
  544. let depthInCollapsedGroup = 0;
  545. for (const [origin, logEntries] of compilation.logging) {
  546. const debugMode = loggingDebug.some(fn => fn(origin));
  547. if (logging === false && !debugMode) continue;
  548. /** @type {KnownStatsLoggingEntry[]} */
  549. const groupStack = [];
  550. /** @type {KnownStatsLoggingEntry[]} */
  551. const rootList = [];
  552. let currentList = rootList;
  553. let processedLogEntries = 0;
  554. for (const entry of logEntries) {
  555. let type = entry.type;
  556. if (!debugMode && !acceptedTypes.has(type)) continue;
  557. // Expand groups in verbose and debug modes
  558. if (
  559. type === LogType.groupCollapsed &&
  560. (debugMode || collapsedGroups)
  561. )
  562. type = LogType.group;
  563. if (depthInCollapsedGroup === 0) {
  564. processedLogEntries++;
  565. }
  566. if (type === LogType.groupEnd) {
  567. groupStack.pop();
  568. currentList =
  569. groupStack.length > 0
  570. ? /** @type {KnownStatsLoggingEntry[]} */ (
  571. groupStack[groupStack.length - 1].children
  572. )
  573. : rootList;
  574. if (depthInCollapsedGroup > 0) depthInCollapsedGroup--;
  575. continue;
  576. }
  577. let message;
  578. if (entry.type === LogType.time) {
  579. const [label, first, second] =
  580. /** @type {[string, number, number]} */
  581. (entry.args);
  582. message = `${label}: ${first * 1000 + second / 1000000} ms`;
  583. } else if (entry.args && entry.args.length > 0) {
  584. message = util.format(entry.args[0], ...entry.args.slice(1));
  585. }
  586. /** @type {KnownStatsLoggingEntry} */
  587. const newEntry = {
  588. ...entry,
  589. type,
  590. message,
  591. trace: loggingTrace ? entry.trace : undefined,
  592. children:
  593. type === LogType.group || type === LogType.groupCollapsed
  594. ? []
  595. : undefined
  596. };
  597. currentList.push(newEntry);
  598. if (newEntry.children) {
  599. groupStack.push(newEntry);
  600. currentList = newEntry.children;
  601. if (depthInCollapsedGroup > 0) {
  602. depthInCollapsedGroup++;
  603. } else if (type === LogType.groupCollapsed) {
  604. depthInCollapsedGroup = 1;
  605. }
  606. }
  607. }
  608. let name = cachedMakePathsRelative(origin).replace(/\|/g, " ");
  609. if (name in object.logging) {
  610. let i = 1;
  611. while (`${name}#${i}` in object.logging) {
  612. i++;
  613. }
  614. name = `${name}#${i}`;
  615. }
  616. object.logging[name] = {
  617. entries: rootList,
  618. filteredEntries: logEntries.length - processedLogEntries,
  619. debug: debugMode
  620. };
  621. }
  622. }
  623. },
  624. hash: (object, compilation) => {
  625. object.hash = /** @type {string} */ (compilation.hash);
  626. },
  627. version: object => {
  628. object.version = require("../../package.json").version;
  629. },
  630. env: (object, compilation, context, { _env }) => {
  631. object.env = _env;
  632. },
  633. timings: (object, compilation) => {
  634. object.time =
  635. /** @type {number} */ (compilation.endTime) -
  636. /** @type {number} */ (compilation.startTime);
  637. },
  638. builtAt: (object, compilation) => {
  639. object.builtAt = /** @type {number} */ (compilation.endTime);
  640. },
  641. publicPath: (object, compilation) => {
  642. object.publicPath = compilation.getPath(
  643. /** @type {TemplatePath} */
  644. (compilation.outputOptions.publicPath)
  645. );
  646. },
  647. outputPath: (object, compilation) => {
  648. object.outputPath = /** @type {string} */ (
  649. compilation.outputOptions.path
  650. );
  651. },
  652. assets: (object, compilation, context, options, factory) => {
  653. const { type } = context;
  654. /** @type {Map<string, Chunk[]>} */
  655. const compilationFileToChunks = new Map();
  656. /** @type {Map<string, Chunk[]>} */
  657. const compilationAuxiliaryFileToChunks = new Map();
  658. for (const chunk of compilation.chunks) {
  659. for (const file of chunk.files) {
  660. let array = compilationFileToChunks.get(file);
  661. if (array === undefined) {
  662. array = [];
  663. compilationFileToChunks.set(file, array);
  664. }
  665. array.push(chunk);
  666. }
  667. for (const file of chunk.auxiliaryFiles) {
  668. let array = compilationAuxiliaryFileToChunks.get(file);
  669. if (array === undefined) {
  670. array = [];
  671. compilationAuxiliaryFileToChunks.set(file, array);
  672. }
  673. array.push(chunk);
  674. }
  675. }
  676. /** @type {Map<string, PreprocessedAsset>} */
  677. const assetMap = new Map();
  678. /** @type {Set<PreprocessedAsset>} */
  679. const assets = new Set();
  680. for (const asset of compilation.getAssets()) {
  681. /** @type {PreprocessedAsset} */
  682. const item = {
  683. ...asset,
  684. type: "asset",
  685. related: undefined
  686. };
  687. assets.add(item);
  688. assetMap.set(asset.name, item);
  689. }
  690. for (const item of assetMap.values()) {
  691. const related = item.info.related;
  692. if (!related) continue;
  693. for (const type of Object.keys(related)) {
  694. const relatedEntry = related[type];
  695. const deps = Array.isArray(relatedEntry)
  696. ? relatedEntry
  697. : [relatedEntry];
  698. for (const dep of deps) {
  699. const depItem = assetMap.get(dep);
  700. if (!depItem) continue;
  701. assets.delete(depItem);
  702. depItem.type = type;
  703. item.related = item.related || [];
  704. item.related.push(depItem);
  705. }
  706. }
  707. }
  708. object.assetsByChunkName = {};
  709. for (const [file, chunks] of compilationFileToChunks) {
  710. for (const chunk of chunks) {
  711. const name = chunk.name;
  712. if (!name) continue;
  713. if (
  714. !Object.prototype.hasOwnProperty.call(
  715. object.assetsByChunkName,
  716. name
  717. )
  718. ) {
  719. object.assetsByChunkName[name] = [];
  720. }
  721. object.assetsByChunkName[name].push(file);
  722. }
  723. }
  724. const groupedAssets = factory.create(
  725. `${type}.assets`,
  726. Array.from(assets),
  727. {
  728. ...context,
  729. compilationFileToChunks,
  730. compilationAuxiliaryFileToChunks
  731. }
  732. );
  733. const limited = spaceLimited(
  734. groupedAssets,
  735. /** @type {number} */ (options.assetsSpace)
  736. );
  737. object.assets = limited.children;
  738. object.filteredAssets = limited.filteredChildren;
  739. },
  740. chunks: (object, compilation, context, options, factory) => {
  741. const { type } = context;
  742. object.chunks = factory.create(
  743. `${type}.chunks`,
  744. Array.from(compilation.chunks),
  745. context
  746. );
  747. },
  748. modules: (object, compilation, context, options, factory) => {
  749. const { type } = context;
  750. const array = Array.from(compilation.modules);
  751. const groupedModules = factory.create(`${type}.modules`, array, context);
  752. const limited = spaceLimited(groupedModules, options.modulesSpace);
  753. object.modules = limited.children;
  754. object.filteredModules = limited.filteredChildren;
  755. },
  756. entrypoints: (
  757. object,
  758. compilation,
  759. context,
  760. { entrypoints, chunkGroups, chunkGroupAuxiliary, chunkGroupChildren },
  761. factory
  762. ) => {
  763. const { type } = context;
  764. const array = Array.from(compilation.entrypoints, ([key, value]) => ({
  765. name: key,
  766. chunkGroup: value
  767. }));
  768. if (entrypoints === "auto" && !chunkGroups) {
  769. if (array.length > 5) return;
  770. if (
  771. !chunkGroupChildren &&
  772. array.every(({ chunkGroup }) => {
  773. if (chunkGroup.chunks.length !== 1) return false;
  774. const chunk = chunkGroup.chunks[0];
  775. return (
  776. chunk.files.size === 1 &&
  777. (!chunkGroupAuxiliary || chunk.auxiliaryFiles.size === 0)
  778. );
  779. })
  780. ) {
  781. return;
  782. }
  783. }
  784. object.entrypoints = factory.create(
  785. `${type}.entrypoints`,
  786. array,
  787. context
  788. );
  789. },
  790. chunkGroups: (object, compilation, context, options, factory) => {
  791. const { type } = context;
  792. const array = Array.from(
  793. compilation.namedChunkGroups,
  794. ([key, value]) => ({
  795. name: key,
  796. chunkGroup: value
  797. })
  798. );
  799. object.namedChunkGroups = factory.create(
  800. `${type}.namedChunkGroups`,
  801. array,
  802. context
  803. );
  804. },
  805. errors: (object, compilation, context, options, factory) => {
  806. const { type, cachedGetErrors } = context;
  807. const rawErrors = cachedGetErrors(compilation);
  808. const factorizedErrors = factory.create(
  809. `${type}.errors`,
  810. cachedGetErrors(compilation),
  811. context
  812. );
  813. let filtered = 0;
  814. if (options.errorDetails === "auto" && rawErrors.length >= 3) {
  815. filtered = rawErrors
  816. .map(e => typeof e !== "string" && e.details)
  817. .filter(Boolean).length;
  818. }
  819. if (
  820. options.errorDetails === true ||
  821. !Number.isFinite(options.errorsSpace)
  822. ) {
  823. object.errors = factorizedErrors;
  824. if (filtered) object.filteredErrorDetailsCount = filtered;
  825. return;
  826. }
  827. const [errors, filteredBySpace] = errorsSpaceLimit(
  828. factorizedErrors,
  829. /** @type {number} */
  830. (options.errorsSpace)
  831. );
  832. object.filteredErrorDetailsCount = filtered + filteredBySpace;
  833. object.errors = errors;
  834. },
  835. errorsCount: (object, compilation, { cachedGetErrors }) => {
  836. object.errorsCount = countWithChildren(compilation, c =>
  837. cachedGetErrors(c)
  838. );
  839. },
  840. warnings: (object, compilation, context, options, factory) => {
  841. const { type, cachedGetWarnings } = context;
  842. const rawWarnings = factory.create(
  843. `${type}.warnings`,
  844. cachedGetWarnings(compilation),
  845. context
  846. );
  847. let filtered = 0;
  848. if (options.errorDetails === "auto") {
  849. filtered = cachedGetWarnings(compilation)
  850. .map(e => typeof e !== "string" && e.details)
  851. .filter(Boolean).length;
  852. }
  853. if (
  854. options.errorDetails === true ||
  855. !Number.isFinite(options.warningsSpace)
  856. ) {
  857. object.warnings = rawWarnings;
  858. if (filtered) object.filteredWarningDetailsCount = filtered;
  859. return;
  860. }
  861. const [warnings, filteredBySpace] = errorsSpaceLimit(
  862. rawWarnings,
  863. /** @type {number} */
  864. (options.warningsSpace)
  865. );
  866. object.filteredWarningDetailsCount = filtered + filteredBySpace;
  867. object.warnings = warnings;
  868. },
  869. warningsCount: (
  870. object,
  871. compilation,
  872. context,
  873. { warningsFilter },
  874. factory
  875. ) => {
  876. const { type, cachedGetWarnings } = context;
  877. object.warningsCount = countWithChildren(compilation, (c, childType) => {
  878. if (
  879. !warningsFilter &&
  880. /** @type {KnownNormalizedStatsOptions["warningsFilter"]} */
  881. (warningsFilter).length === 0
  882. )
  883. return cachedGetWarnings(c);
  884. return factory
  885. .create(`${type}${childType}.warnings`, cachedGetWarnings(c), context)
  886. .filter(
  887. /**
  888. * @param {TODO} warning warning
  889. * @returns {boolean} result
  890. */
  891. warning => {
  892. const warningString = Object.keys(warning)
  893. .map(
  894. key =>
  895. `${warning[/** @type {keyof KnownStatsError} */ (key)]}`
  896. )
  897. .join("\n");
  898. return !warningsFilter.some(filter =>
  899. filter(warning, warningString)
  900. );
  901. }
  902. );
  903. });
  904. },
  905. children: (object, compilation, context, options, factory) => {
  906. const { type } = context;
  907. object.children = factory.create(
  908. `${type}.children`,
  909. compilation.children,
  910. context
  911. );
  912. }
  913. },
  914. asset: {
  915. _: (object, asset, context, options, factory) => {
  916. const { compilation } = context;
  917. object.type = asset.type;
  918. object.name = asset.name;
  919. object.size = asset.source.size();
  920. object.emitted = compilation.emittedAssets.has(asset.name);
  921. object.comparedForEmit = compilation.comparedForEmitAssets.has(
  922. asset.name
  923. );
  924. const cached = !object.emitted && !object.comparedForEmit;
  925. object.cached = cached;
  926. object.info = asset.info;
  927. if (!cached || options.cachedAssets) {
  928. Object.assign(
  929. object,
  930. factory.create(`${context.type}$visible`, asset, context)
  931. );
  932. }
  933. }
  934. },
  935. asset$visible: {
  936. _: (
  937. object,
  938. asset,
  939. { compilation, compilationFileToChunks, compilationAuxiliaryFileToChunks }
  940. ) => {
  941. const chunks = compilationFileToChunks.get(asset.name) || [];
  942. const auxiliaryChunks =
  943. compilationAuxiliaryFileToChunks.get(asset.name) || [];
  944. object.chunkNames = uniqueOrderedArray(
  945. chunks,
  946. c => (c.name ? [c.name] : []),
  947. compareIds
  948. );
  949. object.chunkIdHints = uniqueOrderedArray(
  950. chunks,
  951. c => Array.from(c.idNameHints),
  952. compareIds
  953. );
  954. object.auxiliaryChunkNames = uniqueOrderedArray(
  955. auxiliaryChunks,
  956. c => (c.name ? [c.name] : []),
  957. compareIds
  958. );
  959. object.auxiliaryChunkIdHints = uniqueOrderedArray(
  960. auxiliaryChunks,
  961. c => Array.from(c.idNameHints),
  962. compareIds
  963. );
  964. object.filteredRelated = asset.related ? asset.related.length : undefined;
  965. },
  966. relatedAssets: (object, asset, context, options, factory) => {
  967. const { type } = context;
  968. object.related = factory.create(
  969. `${type.slice(0, -8)}.related`,
  970. asset.related || [],
  971. context
  972. );
  973. object.filteredRelated = asset.related
  974. ? asset.related.length -
  975. /** @type {StatsAsset[]} */ (object.related).length
  976. : undefined;
  977. },
  978. ids: (
  979. object,
  980. asset,
  981. { compilationFileToChunks, compilationAuxiliaryFileToChunks }
  982. ) => {
  983. const chunks = compilationFileToChunks.get(asset.name) || [];
  984. const auxiliaryChunks =
  985. compilationAuxiliaryFileToChunks.get(asset.name) || [];
  986. object.chunks = uniqueOrderedArray(
  987. chunks,
  988. c => /** @type {ChunkId[]} */ (c.ids),
  989. compareIds
  990. );
  991. object.auxiliaryChunks = uniqueOrderedArray(
  992. auxiliaryChunks,
  993. c => /** @type {ChunkId[]} */ (c.ids),
  994. compareIds
  995. );
  996. },
  997. performance: (object, asset) => {
  998. object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(asset.source);
  999. }
  1000. },
  1001. chunkGroup: {
  1002. _: (
  1003. object,
  1004. { name, chunkGroup },
  1005. { compilation, compilation: { moduleGraph, chunkGraph } },
  1006. { ids, chunkGroupAuxiliary, chunkGroupChildren, chunkGroupMaxAssets }
  1007. ) => {
  1008. const children =
  1009. chunkGroupChildren &&
  1010. chunkGroup.getChildrenByOrders(moduleGraph, chunkGraph);
  1011. /**
  1012. * @param {string} name Name
  1013. * @returns {{ name: string, size: number }} Asset object
  1014. */
  1015. const toAsset = name => {
  1016. const asset = compilation.getAsset(name);
  1017. return {
  1018. name,
  1019. size: /** @type {number} */ (asset ? asset.info.size : -1)
  1020. };
  1021. };
  1022. /** @type {(total: number, asset: { size: number }) => number} */
  1023. const sizeReducer = (total, { size }) => total + size;
  1024. const assets = uniqueArray(chunkGroup.chunks, c => c.files).map(toAsset);
  1025. const auxiliaryAssets = uniqueOrderedArray(
  1026. chunkGroup.chunks,
  1027. c => c.auxiliaryFiles,
  1028. compareIds
  1029. ).map(toAsset);
  1030. const assetsSize = assets.reduce(sizeReducer, 0);
  1031. const auxiliaryAssetsSize = auxiliaryAssets.reduce(sizeReducer, 0);
  1032. /** @type {KnownStatsChunkGroup} */
  1033. const statsChunkGroup = {
  1034. name,
  1035. chunks: ids
  1036. ? /** @type {ChunkId[]} */ (chunkGroup.chunks.map(c => c.id))
  1037. : undefined,
  1038. assets: assets.length <= chunkGroupMaxAssets ? assets : undefined,
  1039. filteredAssets:
  1040. assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
  1041. assetsSize,
  1042. auxiliaryAssets:
  1043. chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
  1044. ? auxiliaryAssets
  1045. : undefined,
  1046. filteredAuxiliaryAssets:
  1047. chunkGroupAuxiliary && auxiliaryAssets.length <= chunkGroupMaxAssets
  1048. ? 0
  1049. : auxiliaryAssets.length,
  1050. auxiliaryAssetsSize,
  1051. children: children
  1052. ? mapObject(children, groups =>
  1053. groups.map(group => {
  1054. const assets = uniqueArray(group.chunks, c => c.files).map(
  1055. toAsset
  1056. );
  1057. const auxiliaryAssets = uniqueOrderedArray(
  1058. group.chunks,
  1059. c => c.auxiliaryFiles,
  1060. compareIds
  1061. ).map(toAsset);
  1062. /** @type {KnownStatsChunkGroup} */
  1063. const childStatsChunkGroup = {
  1064. name: group.name,
  1065. chunks: ids
  1066. ? /** @type {ChunkId[]} */
  1067. (group.chunks.map(c => c.id))
  1068. : undefined,
  1069. assets:
  1070. assets.length <= chunkGroupMaxAssets ? assets : undefined,
  1071. filteredAssets:
  1072. assets.length <= chunkGroupMaxAssets ? 0 : assets.length,
  1073. auxiliaryAssets:
  1074. chunkGroupAuxiliary &&
  1075. auxiliaryAssets.length <= chunkGroupMaxAssets
  1076. ? auxiliaryAssets
  1077. : undefined,
  1078. filteredAuxiliaryAssets:
  1079. chunkGroupAuxiliary &&
  1080. auxiliaryAssets.length <= chunkGroupMaxAssets
  1081. ? 0
  1082. : auxiliaryAssets.length
  1083. };
  1084. return childStatsChunkGroup;
  1085. })
  1086. )
  1087. : undefined,
  1088. childAssets: children
  1089. ? mapObject(children, groups => {
  1090. /** @type {Set<string>} */
  1091. const set = new Set();
  1092. for (const group of groups) {
  1093. for (const chunk of group.chunks) {
  1094. for (const asset of chunk.files) {
  1095. set.add(asset);
  1096. }
  1097. }
  1098. }
  1099. return Array.from(set);
  1100. })
  1101. : undefined
  1102. };
  1103. Object.assign(object, statsChunkGroup);
  1104. },
  1105. performance: (object, { chunkGroup }) => {
  1106. object.isOverSizeLimit = SizeLimitsPlugin.isOverSizeLimit(chunkGroup);
  1107. }
  1108. },
  1109. module: {
  1110. _: (object, module, context, options, factory) => {
  1111. const { type } = context;
  1112. const compilation = /** @type {Compilation} */ (context.compilation);
  1113. const built = compilation.builtModules.has(module);
  1114. const codeGenerated = compilation.codeGeneratedModules.has(module);
  1115. const buildTimeExecuted =
  1116. compilation.buildTimeExecutedModules.has(module);
  1117. /** @type {{[x: string]: number}} */
  1118. const sizes = {};
  1119. for (const sourceType of module.getSourceTypes()) {
  1120. sizes[sourceType] = module.size(sourceType);
  1121. }
  1122. /** @type {KnownStatsModule} */
  1123. const statsModule = {
  1124. type: "module",
  1125. moduleType: module.type,
  1126. layer: module.layer,
  1127. size: module.size(),
  1128. sizes,
  1129. built,
  1130. codeGenerated,
  1131. buildTimeExecuted,
  1132. cached: !built && !codeGenerated
  1133. };
  1134. Object.assign(object, statsModule);
  1135. if (built || codeGenerated || options.cachedModules) {
  1136. Object.assign(
  1137. object,
  1138. factory.create(`${type}$visible`, module, context)
  1139. );
  1140. }
  1141. }
  1142. },
  1143. module$visible: {
  1144. _: (object, module, context, { requestShortener }, factory) => {
  1145. const { type, rootModules } = context;
  1146. const compilation = /** @type {Compilation} */ (context.compilation);
  1147. const { moduleGraph } = compilation;
  1148. /** @type {Module[]} */
  1149. const path = [];
  1150. const issuer = moduleGraph.getIssuer(module);
  1151. let current = issuer;
  1152. while (current) {
  1153. path.push(current);
  1154. current = moduleGraph.getIssuer(current);
  1155. }
  1156. path.reverse();
  1157. const profile = moduleGraph.getProfile(module);
  1158. const errors = module.getErrors();
  1159. const errorsCount = errors !== undefined ? countIterable(errors) : 0;
  1160. const warnings = module.getWarnings();
  1161. const warningsCount =
  1162. warnings !== undefined ? countIterable(warnings) : 0;
  1163. /** @type {KnownStatsModule} */
  1164. const statsModule = {
  1165. identifier: module.identifier(),
  1166. name: module.readableIdentifier(requestShortener),
  1167. nameForCondition: module.nameForCondition(),
  1168. index: /** @type {number} */ (moduleGraph.getPreOrderIndex(module)),
  1169. preOrderIndex: /** @type {number} */ (
  1170. moduleGraph.getPreOrderIndex(module)
  1171. ),
  1172. index2: /** @type {number} */ (moduleGraph.getPostOrderIndex(module)),
  1173. postOrderIndex: /** @type {number} */ (
  1174. moduleGraph.getPostOrderIndex(module)
  1175. ),
  1176. cacheable: /** @type {BuildInfo} */ (module.buildInfo).cacheable,
  1177. optional: module.isOptional(moduleGraph),
  1178. orphan:
  1179. !type.endsWith("module.modules[].module$visible") &&
  1180. compilation.chunkGraph.getNumberOfModuleChunks(module) === 0,
  1181. dependent: rootModules ? !rootModules.has(module) : undefined,
  1182. issuer: issuer && issuer.identifier(),
  1183. issuerName: issuer && issuer.readableIdentifier(requestShortener),
  1184. issuerPath:
  1185. issuer &&
  1186. factory.create(`${type.slice(0, -8)}.issuerPath`, path, context),
  1187. failed: errorsCount > 0,
  1188. errors: errorsCount,
  1189. warnings: warningsCount
  1190. };
  1191. Object.assign(object, statsModule);
  1192. if (profile) {
  1193. object.profile = factory.create(
  1194. `${type.slice(0, -8)}.profile`,
  1195. profile,
  1196. context
  1197. );
  1198. }
  1199. },
  1200. ids: (object, module, { compilation: { chunkGraph, moduleGraph } }) => {
  1201. object.id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
  1202. const issuer = moduleGraph.getIssuer(module);
  1203. object.issuerId = issuer && chunkGraph.getModuleId(issuer);
  1204. object.chunks =
  1205. /** @type {ChunkId[]} */
  1206. (
  1207. Array.from(
  1208. chunkGraph.getOrderedModuleChunksIterable(
  1209. module,
  1210. compareChunksById
  1211. ),
  1212. chunk => chunk.id
  1213. )
  1214. );
  1215. },
  1216. moduleAssets: (object, module) => {
  1217. object.assets = /** @type {BuildInfo} */ (module.buildInfo).assets
  1218. ? Object.keys(/** @type {BuildInfo} */ (module.buildInfo).assets)
  1219. : [];
  1220. },
  1221. reasons: (object, module, context, options, factory) => {
  1222. const {
  1223. type,
  1224. compilation: { moduleGraph }
  1225. } = context;
  1226. const groupsReasons = factory.create(
  1227. `${type.slice(0, -8)}.reasons`,
  1228. Array.from(moduleGraph.getIncomingConnections(module)),
  1229. context
  1230. );
  1231. const limited = spaceLimited(
  1232. groupsReasons,
  1233. /** @type {number} */
  1234. (options.reasonsSpace)
  1235. );
  1236. object.reasons = limited.children;
  1237. object.filteredReasons = limited.filteredChildren;
  1238. },
  1239. usedExports: (
  1240. object,
  1241. module,
  1242. { runtime, compilation: { moduleGraph } }
  1243. ) => {
  1244. const usedExports = moduleGraph.getUsedExports(module, runtime);
  1245. if (usedExports === null) {
  1246. object.usedExports = null;
  1247. } else if (typeof usedExports === "boolean") {
  1248. object.usedExports = usedExports;
  1249. } else {
  1250. object.usedExports = Array.from(usedExports);
  1251. }
  1252. },
  1253. providedExports: (object, module, { compilation: { moduleGraph } }) => {
  1254. const providedExports = moduleGraph.getProvidedExports(module);
  1255. object.providedExports = Array.isArray(providedExports)
  1256. ? providedExports
  1257. : null;
  1258. },
  1259. optimizationBailout: (
  1260. object,
  1261. module,
  1262. { compilation: { moduleGraph } },
  1263. { requestShortener }
  1264. ) => {
  1265. object.optimizationBailout = moduleGraph
  1266. .getOptimizationBailout(module)
  1267. .map(item => {
  1268. if (typeof item === "function") return item(requestShortener);
  1269. return item;
  1270. });
  1271. },
  1272. depth: (object, module, { compilation: { moduleGraph } }) => {
  1273. object.depth = moduleGraph.getDepth(module);
  1274. },
  1275. nestedModules: (object, module, context, options, factory) => {
  1276. const { type } = context;
  1277. const innerModules = /** @type {Module & { modules?: Module[] }} */ (
  1278. module
  1279. ).modules;
  1280. if (Array.isArray(innerModules)) {
  1281. const groupedModules = factory.create(
  1282. `${type.slice(0, -8)}.modules`,
  1283. innerModules,
  1284. context
  1285. );
  1286. const limited = spaceLimited(
  1287. groupedModules,
  1288. options.nestedModulesSpace
  1289. );
  1290. object.modules = limited.children;
  1291. object.filteredModules = limited.filteredChildren;
  1292. }
  1293. },
  1294. source: (object, module) => {
  1295. const originalSource = module.originalSource();
  1296. if (originalSource) {
  1297. object.source = originalSource.source();
  1298. }
  1299. }
  1300. },
  1301. profile: {
  1302. _: (object, profile) => {
  1303. /** @type {KnownStatsProfile} */
  1304. const statsProfile = {
  1305. total:
  1306. profile.factory +
  1307. profile.restoring +
  1308. profile.integration +
  1309. profile.building +
  1310. profile.storing,
  1311. resolving: profile.factory,
  1312. restoring: profile.restoring,
  1313. building: profile.building,
  1314. integration: profile.integration,
  1315. storing: profile.storing,
  1316. additionalResolving: profile.additionalFactories,
  1317. additionalIntegration: profile.additionalIntegration,
  1318. // TODO remove this in webpack 6
  1319. factory: profile.factory,
  1320. // TODO remove this in webpack 6
  1321. dependencies: profile.additionalFactories
  1322. };
  1323. Object.assign(object, statsProfile);
  1324. }
  1325. },
  1326. moduleIssuer: {
  1327. _: (object, module, context, { requestShortener }, factory) => {
  1328. const { type } = context;
  1329. const compilation = /** @type {Compilation} */ (context.compilation);
  1330. const { moduleGraph } = compilation;
  1331. const profile = moduleGraph.getProfile(module);
  1332. /** @type {Partial<KnownStatsModuleIssuer>} */
  1333. const statsModuleIssuer = {
  1334. identifier: module.identifier(),
  1335. name: module.readableIdentifier(requestShortener)
  1336. };
  1337. Object.assign(object, statsModuleIssuer);
  1338. if (profile) {
  1339. object.profile = factory.create(`${type}.profile`, profile, context);
  1340. }
  1341. },
  1342. ids: (object, module, { compilation: { chunkGraph } }) => {
  1343. object.id = /** @type {ModuleId} */ (chunkGraph.getModuleId(module));
  1344. }
  1345. },
  1346. moduleReason: {
  1347. _: (object, reason, { runtime }, { requestShortener }) => {
  1348. const dep = reason.dependency;
  1349. const moduleDep =
  1350. dep && dep instanceof ModuleDependency ? dep : undefined;
  1351. /** @type {KnownStatsModuleReason} */
  1352. const statsModuleReason = {
  1353. moduleIdentifier: reason.originModule
  1354. ? reason.originModule.identifier()
  1355. : null,
  1356. module: reason.originModule
  1357. ? reason.originModule.readableIdentifier(requestShortener)
  1358. : null,
  1359. moduleName: reason.originModule
  1360. ? reason.originModule.readableIdentifier(requestShortener)
  1361. : null,
  1362. resolvedModuleIdentifier: reason.resolvedOriginModule
  1363. ? reason.resolvedOriginModule.identifier()
  1364. : null,
  1365. resolvedModule: reason.resolvedOriginModule
  1366. ? reason.resolvedOriginModule.readableIdentifier(requestShortener)
  1367. : null,
  1368. type: reason.dependency ? reason.dependency.type : null,
  1369. active: reason.isActive(runtime),
  1370. explanation: reason.explanation,
  1371. userRequest: (moduleDep && moduleDep.userRequest) || null
  1372. };
  1373. Object.assign(object, statsModuleReason);
  1374. if (reason.dependency) {
  1375. const locInfo = formatLocation(reason.dependency.loc);
  1376. if (locInfo) {
  1377. object.loc = locInfo;
  1378. }
  1379. }
  1380. },
  1381. ids: (object, reason, { compilation: { chunkGraph } }) => {
  1382. object.moduleId = reason.originModule
  1383. ? chunkGraph.getModuleId(reason.originModule)
  1384. : null;
  1385. object.resolvedModuleId = reason.resolvedOriginModule
  1386. ? chunkGraph.getModuleId(reason.resolvedOriginModule)
  1387. : null;
  1388. }
  1389. },
  1390. chunk: {
  1391. _: (object, chunk, { makePathsRelative, compilation: { chunkGraph } }) => {
  1392. const childIdByOrder = chunk.getChildIdsByOrders(chunkGraph);
  1393. /** @type {KnownStatsChunk} */
  1394. const statsChunk = {
  1395. rendered: chunk.rendered,
  1396. initial: chunk.canBeInitial(),
  1397. entry: chunk.hasRuntime(),
  1398. recorded: AggressiveSplittingPlugin.wasChunkRecorded(chunk),
  1399. reason: chunk.chunkReason,
  1400. size: chunkGraph.getChunkModulesSize(chunk),
  1401. sizes: chunkGraph.getChunkModulesSizes(chunk),
  1402. names: chunk.name ? [chunk.name] : [],
  1403. idHints: Array.from(chunk.idNameHints),
  1404. runtime:
  1405. chunk.runtime === undefined
  1406. ? undefined
  1407. : typeof chunk.runtime === "string"
  1408. ? [makePathsRelative(chunk.runtime)]
  1409. : Array.from(chunk.runtime.sort(), makePathsRelative),
  1410. files: Array.from(chunk.files),
  1411. auxiliaryFiles: Array.from(chunk.auxiliaryFiles).sort(compareIds),
  1412. hash: /** @type {string} */ (chunk.renderedHash),
  1413. childrenByOrder: childIdByOrder
  1414. };
  1415. Object.assign(object, statsChunk);
  1416. },
  1417. ids: (object, chunk) => {
  1418. object.id = /** @type {ChunkId} */ (chunk.id);
  1419. },
  1420. chunkRelations: (object, chunk, { compilation: { chunkGraph } }) => {
  1421. /** @type {Set<string|number>} */
  1422. const parents = new Set();
  1423. /** @type {Set<string|number>} */
  1424. const children = new Set();
  1425. /** @type {Set<string|number>} */
  1426. const siblings = new Set();
  1427. for (const chunkGroup of chunk.groupsIterable) {
  1428. for (const parentGroup of chunkGroup.parentsIterable) {
  1429. for (const chunk of parentGroup.chunks) {
  1430. parents.add(/** @type {ChunkId} */ (chunk.id));
  1431. }
  1432. }
  1433. for (const childGroup of chunkGroup.childrenIterable) {
  1434. for (const chunk of childGroup.chunks) {
  1435. children.add(/** @type {ChunkId} */ (chunk.id));
  1436. }
  1437. }
  1438. for (const sibling of chunkGroup.chunks) {
  1439. if (sibling !== chunk)
  1440. siblings.add(/** @type {ChunkId} */ (sibling.id));
  1441. }
  1442. }
  1443. object.siblings = Array.from(siblings).sort(compareIds);
  1444. object.parents = Array.from(parents).sort(compareIds);
  1445. object.children = Array.from(children).sort(compareIds);
  1446. },
  1447. chunkModules: (object, chunk, context, options, factory) => {
  1448. const {
  1449. type,
  1450. compilation: { chunkGraph }
  1451. } = context;
  1452. const array = chunkGraph.getChunkModules(chunk);
  1453. const groupedModules = factory.create(`${type}.modules`, array, {
  1454. ...context,
  1455. runtime: chunk.runtime,
  1456. rootModules: new Set(chunkGraph.getChunkRootModules(chunk))
  1457. });
  1458. const limited = spaceLimited(groupedModules, options.chunkModulesSpace);
  1459. object.modules = limited.children;
  1460. object.filteredModules = limited.filteredChildren;
  1461. },
  1462. chunkOrigins: (object, chunk, context, options, factory) => {
  1463. const {
  1464. type,
  1465. compilation: { chunkGraph }
  1466. } = context;
  1467. /** @type {Set<string>} */
  1468. const originsKeySet = new Set();
  1469. const origins = [];
  1470. for (const g of chunk.groupsIterable) {
  1471. origins.push(...g.origins);
  1472. }
  1473. const array = origins.filter(origin => {
  1474. const key = [
  1475. origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
  1476. formatLocation(origin.loc),
  1477. origin.request
  1478. ].join();
  1479. if (originsKeySet.has(key)) return false;
  1480. originsKeySet.add(key);
  1481. return true;
  1482. });
  1483. object.origins = factory.create(`${type}.origins`, array, context);
  1484. }
  1485. },
  1486. chunkOrigin: {
  1487. _: (object, origin, context, { requestShortener }) => {
  1488. /** @type {KnownStatsChunkOrigin} */
  1489. const statsChunkOrigin = {
  1490. module: origin.module ? origin.module.identifier() : "",
  1491. moduleIdentifier: origin.module ? origin.module.identifier() : "",
  1492. moduleName: origin.module
  1493. ? origin.module.readableIdentifier(requestShortener)
  1494. : "",
  1495. loc: formatLocation(origin.loc),
  1496. request: origin.request
  1497. };
  1498. Object.assign(object, statsChunkOrigin);
  1499. },
  1500. ids: (object, origin, { compilation: { chunkGraph } }) => {
  1501. object.moduleId = origin.module
  1502. ? /** @type {ModuleId} */ (chunkGraph.getModuleId(origin.module))
  1503. : undefined;
  1504. }
  1505. },
  1506. error: EXTRACT_ERROR,
  1507. warning: EXTRACT_ERROR,
  1508. moduleTraceItem: {
  1509. _: (object, { origin, module }, context, { requestShortener }, factory) => {
  1510. const {
  1511. type,
  1512. compilation: { moduleGraph }
  1513. } = context;
  1514. object.originIdentifier = origin.identifier();
  1515. object.originName = origin.readableIdentifier(requestShortener);
  1516. object.moduleIdentifier = module.identifier();
  1517. object.moduleName = module.readableIdentifier(requestShortener);
  1518. const dependencies = Array.from(
  1519. moduleGraph.getIncomingConnections(module)
  1520. )
  1521. .filter(c => c.resolvedOriginModule === origin && c.dependency)
  1522. .map(c => c.dependency);
  1523. object.dependencies = factory.create(
  1524. `${type}.dependencies`,
  1525. Array.from(new Set(dependencies)),
  1526. context
  1527. );
  1528. },
  1529. ids: (object, { origin, module }, { compilation: { chunkGraph } }) => {
  1530. object.originId =
  1531. /** @type {ModuleId} */
  1532. (chunkGraph.getModuleId(origin));
  1533. object.moduleId =
  1534. /** @type {ModuleId} */
  1535. (chunkGraph.getModuleId(module));
  1536. }
  1537. },
  1538. moduleTraceDependency: {
  1539. _: (object, dependency) => {
  1540. object.loc = formatLocation(dependency.loc);
  1541. }
  1542. }
  1543. };
  1544. /** @type {Record<string, Record<string, (thing: ModuleGraphConnection, context: StatsFactoryContext, options: NormalizedStatsOptions, idx: number, i: number) => boolean | undefined>>} */
  1545. const FILTER = {
  1546. "module.reasons": {
  1547. "!orphanModules": (reason, { compilation: { chunkGraph } }) => {
  1548. if (
  1549. reason.originModule &&
  1550. chunkGraph.getNumberOfModuleChunks(reason.originModule) === 0
  1551. ) {
  1552. return false;
  1553. }
  1554. }
  1555. }
  1556. };
  1557. /** @type {Record<string, Record<string, (thing: KnownStatsError, context: StatsFactoryContext, options: NormalizedStatsOptions, idx: number, i: number) => boolean | undefined>>} */
  1558. const FILTER_RESULTS = {
  1559. "compilation.warnings": {
  1560. warningsFilter: util.deprecate(
  1561. (warning, context, { warningsFilter }) => {
  1562. const warningString = Object.keys(warning)
  1563. .map(key => `${warning[/** @type {keyof KnownStatsError} */ (key)]}`)
  1564. .join("\n");
  1565. return !warningsFilter.some(filter => filter(warning, warningString));
  1566. },
  1567. "config.stats.warningsFilter is deprecated in favor of config.ignoreWarnings",
  1568. "DEP_WEBPACK_STATS_WARNINGS_FILTER"
  1569. )
  1570. }
  1571. };
  1572. /**
  1573. * @type {Record<string, (comparators: Comparator<Module>[], context: StatsFactoryContext) => void>}
  1574. */
  1575. const MODULES_SORTER = {
  1576. _: (comparators, { compilation: { moduleGraph } }) => {
  1577. comparators.push(
  1578. compareSelect(m => moduleGraph.getDepth(m), compareNumbers),
  1579. compareSelect(m => moduleGraph.getPreOrderIndex(m), compareNumbers),
  1580. compareSelect(m => m.identifier(), compareIds)
  1581. );
  1582. }
  1583. };
  1584. /** @type {Record<string, Record<string, (comparators: Comparator<any>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>>} */
  1585. const SORTERS = {
  1586. "compilation.chunks": {
  1587. _: comparators => {
  1588. comparators.push(compareSelect(c => c.id, compareIds));
  1589. }
  1590. },
  1591. "compilation.modules": MODULES_SORTER,
  1592. "chunk.rootModules": MODULES_SORTER,
  1593. "chunk.modules": MODULES_SORTER,
  1594. "module.modules": MODULES_SORTER,
  1595. "module.reasons": {
  1596. _: (comparators, { compilation: { chunkGraph } }) => {
  1597. comparators.push(
  1598. compareSelect(x => x.originModule, compareModulesByIdentifier)
  1599. );
  1600. comparators.push(
  1601. compareSelect(x => x.resolvedOriginModule, compareModulesByIdentifier)
  1602. );
  1603. comparators.push(
  1604. compareSelect(
  1605. x => x.dependency,
  1606. concatComparators(
  1607. compareSelect(
  1608. /**
  1609. * @param {Dependency} x dependency
  1610. * @returns {DependencyLocation} location
  1611. */
  1612. x => x.loc,
  1613. compareLocations
  1614. ),
  1615. compareSelect(x => x.type, compareIds)
  1616. )
  1617. )
  1618. );
  1619. }
  1620. },
  1621. "chunk.origins": {
  1622. _: (comparators, { compilation: { chunkGraph } }) => {
  1623. comparators.push(
  1624. compareSelect(
  1625. origin =>
  1626. origin.module ? chunkGraph.getModuleId(origin.module) : undefined,
  1627. compareIds
  1628. ),
  1629. compareSelect(origin => formatLocation(origin.loc), compareIds),
  1630. compareSelect(origin => origin.request, compareIds)
  1631. );
  1632. }
  1633. }
  1634. };
  1635. /**
  1636. * @template T
  1637. * @typedef {T & { children: Children<T>[] | undefined, filteredChildren?: number }} Children
  1638. */
  1639. /**
  1640. * @template T
  1641. * @param {Children<T>} item item
  1642. * @returns {number} item size
  1643. */
  1644. const getItemSize = item =>
  1645. // Each item takes 1 line
  1646. // + the size of the children
  1647. // + 1 extra line when it has children and filteredChildren
  1648. !item.children
  1649. ? 1
  1650. : item.filteredChildren
  1651. ? 2 + getTotalSize(item.children)
  1652. : 1 + getTotalSize(item.children);
  1653. /**
  1654. * @template T
  1655. * @param {Children<T>[]} children children
  1656. * @returns {number} total size
  1657. */
  1658. const getTotalSize = children => {
  1659. let size = 0;
  1660. for (const child of children) {
  1661. size += getItemSize(child);
  1662. }
  1663. return size;
  1664. };
  1665. /**
  1666. * @template T
  1667. * @param {Children<T>[]} children children
  1668. * @returns {number} total items
  1669. */
  1670. const getTotalItems = children => {
  1671. let count = 0;
  1672. for (const child of children) {
  1673. if (!child.children && !child.filteredChildren) {
  1674. count++;
  1675. } else {
  1676. if (child.children) count += getTotalItems(child.children);
  1677. if (child.filteredChildren) count += child.filteredChildren;
  1678. }
  1679. }
  1680. return count;
  1681. };
  1682. /**
  1683. * @template T
  1684. * @param {Children<T>[]} children children
  1685. * @returns {Children<T>[]} collapsed children
  1686. */
  1687. const collapse = children => {
  1688. // After collapse each child must take exactly one line
  1689. const newChildren = [];
  1690. for (const child of children) {
  1691. if (child.children) {
  1692. let filteredChildren = child.filteredChildren || 0;
  1693. filteredChildren += getTotalItems(child.children);
  1694. newChildren.push({
  1695. ...child,
  1696. children: undefined,
  1697. filteredChildren
  1698. });
  1699. } else {
  1700. newChildren.push(child);
  1701. }
  1702. }
  1703. return newChildren;
  1704. };
  1705. /**
  1706. * @template T
  1707. * @param {Children<T>[]} itemsAndGroups item and groups
  1708. * @param {number} max max
  1709. * @param {boolean=} filteredChildrenLineReserved filtered children line reserved
  1710. * @returns {Children<T>} result
  1711. */
  1712. const spaceLimited = (
  1713. itemsAndGroups,
  1714. max,
  1715. filteredChildrenLineReserved = false
  1716. ) => {
  1717. if (max < 1) {
  1718. return /** @type {Children<T>} */ ({
  1719. children: undefined,
  1720. filteredChildren: getTotalItems(itemsAndGroups)
  1721. });
  1722. }
  1723. /** @type {Children<T>[] | undefined} */
  1724. let children;
  1725. /** @type {number | undefined} */
  1726. let filteredChildren;
  1727. // This are the groups, which take 1+ lines each
  1728. /** @type {Children<T>[] | undefined} */
  1729. const groups = [];
  1730. // The sizes of the groups are stored in groupSizes
  1731. /** @type {number[]} */
  1732. const groupSizes = [];
  1733. // This are the items, which take 1 line each
  1734. const items = [];
  1735. // The total of group sizes
  1736. let groupsSize = 0;
  1737. for (const itemOrGroup of itemsAndGroups) {
  1738. // is item
  1739. if (!itemOrGroup.children && !itemOrGroup.filteredChildren) {
  1740. items.push(itemOrGroup);
  1741. } else {
  1742. groups.push(itemOrGroup);
  1743. const size = getItemSize(itemOrGroup);
  1744. groupSizes.push(size);
  1745. groupsSize += size;
  1746. }
  1747. }
  1748. if (groupsSize + items.length <= max) {
  1749. // The total size in the current state fits into the max
  1750. // keep all
  1751. children = groups.length > 0 ? groups.concat(items) : items;
  1752. } else if (groups.length === 0) {
  1753. // slice items to max
  1754. // inner space marks that lines for filteredChildren already reserved
  1755. const limit = max - (filteredChildrenLineReserved ? 0 : 1);
  1756. filteredChildren = items.length - limit;
  1757. items.length = limit;
  1758. children = items;
  1759. } else {
  1760. // limit is the size when all groups are collapsed
  1761. const limit =
  1762. groups.length +
  1763. (filteredChildrenLineReserved || items.length === 0 ? 0 : 1);
  1764. if (limit < max) {
  1765. // calculate how much we are over the size limit
  1766. // this allows to approach the limit faster
  1767. let oversize;
  1768. // If each group would take 1 line the total would be below the maximum
  1769. // collapse some groups, keep items
  1770. while (
  1771. (oversize =
  1772. groupsSize +
  1773. items.length +
  1774. (filteredChildren && !filteredChildrenLineReserved ? 1 : 0) -
  1775. max) > 0
  1776. ) {
  1777. // Find the maximum group and process only this one
  1778. const maxGroupSize = Math.max(...groupSizes);
  1779. if (maxGroupSize < items.length) {
  1780. filteredChildren = items.length;
  1781. items.length = 0;
  1782. continue;
  1783. }
  1784. for (let i = 0; i < groups.length; i++) {
  1785. if (groupSizes[i] === maxGroupSize) {
  1786. const group = groups[i];
  1787. // run this algorithm recursively and limit the size of the children to
  1788. // current size - oversize / number of groups
  1789. // So it should always end up being smaller
  1790. const headerSize = group.filteredChildren ? 2 : 1;
  1791. const limited = spaceLimited(
  1792. /** @type {Children<T>[]} */ (group.children),
  1793. maxGroupSize -
  1794. // we should use ceil to always feet in max
  1795. Math.ceil(oversize / groups.length) -
  1796. // we substitute size of group head
  1797. headerSize,
  1798. headerSize === 2
  1799. );
  1800. groups[i] = {
  1801. ...group,
  1802. children: limited.children,
  1803. filteredChildren: limited.filteredChildren
  1804. ? (group.filteredChildren || 0) + limited.filteredChildren
  1805. : group.filteredChildren
  1806. };
  1807. const newSize = getItemSize(groups[i]);
  1808. groupsSize -= maxGroupSize - newSize;
  1809. groupSizes[i] = newSize;
  1810. break;
  1811. }
  1812. }
  1813. }
  1814. children = groups.concat(items);
  1815. } else if (limit === max) {
  1816. // If we have only enough space to show one line per group and one line for the filtered items
  1817. // collapse all groups and items
  1818. children = collapse(groups);
  1819. filteredChildren = items.length;
  1820. } else {
  1821. // If we have no space
  1822. // collapse complete group
  1823. filteredChildren = getTotalItems(itemsAndGroups);
  1824. }
  1825. }
  1826. return /** @type {Children<T>} */ ({ children, filteredChildren });
  1827. };
  1828. /**
  1829. * @param {StatsError[]} errors errors
  1830. * @param {number} max max
  1831. * @returns {[StatsError[], number]} error space limit
  1832. */
  1833. const errorsSpaceLimit = (errors, max) => {
  1834. let filtered = 0;
  1835. // Can not fit into limit
  1836. // print only messages
  1837. if (errors.length + 1 >= max)
  1838. return [
  1839. errors.map(error => {
  1840. if (typeof error === "string" || !error.details) return error;
  1841. filtered++;
  1842. return { ...error, details: "" };
  1843. }),
  1844. filtered
  1845. ];
  1846. let fullLength = errors.length;
  1847. let result = errors;
  1848. let i = 0;
  1849. for (; i < errors.length; i++) {
  1850. const error = errors[i];
  1851. if (typeof error !== "string" && error.details) {
  1852. const splitted = error.details.split("\n");
  1853. const len = splitted.length;
  1854. fullLength += len;
  1855. if (fullLength > max) {
  1856. result = i > 0 ? errors.slice(0, i) : [];
  1857. const overLimit = fullLength - max + 1;
  1858. const error = errors[i++];
  1859. result.push({
  1860. ...error,
  1861. details:
  1862. /** @type {string} */
  1863. (error.details).split("\n").slice(0, -overLimit).join("\n"),
  1864. filteredDetails: overLimit
  1865. });
  1866. filtered = errors.length - i;
  1867. for (; i < errors.length; i++) {
  1868. const error = errors[i];
  1869. if (typeof error === "string" || !error.details) result.push(error);
  1870. result.push({ ...error, details: "" });
  1871. }
  1872. break;
  1873. } else if (fullLength === max) {
  1874. result = errors.slice(0, ++i);
  1875. filtered = errors.length - i;
  1876. for (; i < errors.length; i++) {
  1877. const error = errors[i];
  1878. if (typeof error === "string" || !error.details) result.push(error);
  1879. result.push({ ...error, details: "" });
  1880. }
  1881. break;
  1882. }
  1883. }
  1884. }
  1885. return [result, filtered];
  1886. };
  1887. /**
  1888. * @template {{ size: number }} T
  1889. * @template {{ size: number }} R
  1890. * @param {(R | T)[]} children children
  1891. * @param {T[]} assets assets
  1892. * @returns {{ size: number }} asset size
  1893. */
  1894. const assetGroup = (children, assets) => {
  1895. let size = 0;
  1896. for (const asset of children) {
  1897. size += asset.size;
  1898. }
  1899. return { size };
  1900. };
  1901. /**
  1902. * @template {{ size: number, sizes: Record<string, number> }} T
  1903. * @param {Children<T>[]} children children
  1904. * @param {KnownStatsModule[]} modules modules
  1905. * @returns {{ size: number, sizes: Record<string, number>}} size and sizes
  1906. */
  1907. const moduleGroup = (children, modules) => {
  1908. let size = 0;
  1909. /** @type {Record<string, number>} */
  1910. const sizes = {};
  1911. for (const module of children) {
  1912. size += module.size;
  1913. for (const key of Object.keys(module.sizes)) {
  1914. sizes[key] = (sizes[key] || 0) + module.sizes[key];
  1915. }
  1916. }
  1917. return {
  1918. size,
  1919. sizes
  1920. };
  1921. };
  1922. /**
  1923. * @template {{ active: boolean }} T
  1924. * @param {Children<T>[]} children children
  1925. * @param {KnownStatsModuleReason[]} reasons reasons
  1926. * @returns {{ active: boolean }} reason group
  1927. */
  1928. const reasonGroup = (children, reasons) => {
  1929. let active = false;
  1930. for (const reason of children) {
  1931. active = active || reason.active;
  1932. }
  1933. return {
  1934. active
  1935. };
  1936. };
  1937. const GROUP_EXTENSION_REGEXP = /(\.[^.]+?)(?:\?|(?: \+ \d+ modules?)?$)/;
  1938. const GROUP_PATH_REGEXP = /(.+)[/\\][^/\\]+?(?:\?|(?: \+ \d+ modules?)?$)/;
  1939. /** @typedef {Record<string, (groupConfigs: GroupConfig<KnownStatsAsset, TODO>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} AssetsGroupers */
  1940. /** @type {AssetsGroupers} */
  1941. const ASSETS_GROUPERS = {
  1942. _: (groupConfigs, context, options) => {
  1943. /**
  1944. * @param {keyof KnownStatsAsset} name name
  1945. * @param {boolean=} exclude need exclude?
  1946. */
  1947. const groupByFlag = (name, exclude) => {
  1948. groupConfigs.push({
  1949. getKeys: asset => (asset[name] ? ["1"] : undefined),
  1950. getOptions: () => ({
  1951. groupChildren: !exclude,
  1952. force: exclude
  1953. }),
  1954. createGroup: (key, children, assets) =>
  1955. exclude
  1956. ? {
  1957. type: "assets by status",
  1958. [name]: Boolean(key),
  1959. filteredChildren: assets.length,
  1960. ...assetGroup(children, assets)
  1961. }
  1962. : {
  1963. type: "assets by status",
  1964. [name]: Boolean(key),
  1965. children,
  1966. ...assetGroup(children, assets)
  1967. }
  1968. });
  1969. };
  1970. const {
  1971. groupAssetsByEmitStatus,
  1972. groupAssetsByPath,
  1973. groupAssetsByExtension
  1974. } = options;
  1975. if (groupAssetsByEmitStatus) {
  1976. groupByFlag("emitted");
  1977. groupByFlag("comparedForEmit");
  1978. groupByFlag("isOverSizeLimit");
  1979. }
  1980. if (groupAssetsByEmitStatus || !options.cachedAssets) {
  1981. groupByFlag("cached", !options.cachedAssets);
  1982. }
  1983. if (groupAssetsByPath || groupAssetsByExtension) {
  1984. groupConfigs.push({
  1985. getKeys: asset => {
  1986. const extensionMatch =
  1987. groupAssetsByExtension && GROUP_EXTENSION_REGEXP.exec(asset.name);
  1988. const extension = extensionMatch ? extensionMatch[1] : "";
  1989. const pathMatch =
  1990. groupAssetsByPath && GROUP_PATH_REGEXP.exec(asset.name);
  1991. const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
  1992. const keys = [];
  1993. if (groupAssetsByPath) {
  1994. keys.push(".");
  1995. if (extension)
  1996. keys.push(
  1997. path.length
  1998. ? `${path.join("/")}/*${extension}`
  1999. : `*${extension}`
  2000. );
  2001. while (path.length > 0) {
  2002. keys.push(`${path.join("/")}/`);
  2003. path.pop();
  2004. }
  2005. } else if (extension) {
  2006. keys.push(`*${extension}`);
  2007. }
  2008. return keys;
  2009. },
  2010. createGroup: (key, children, assets) => ({
  2011. type: groupAssetsByPath ? "assets by path" : "assets by extension",
  2012. name: key,
  2013. children,
  2014. ...assetGroup(children, assets)
  2015. })
  2016. });
  2017. }
  2018. },
  2019. groupAssetsByInfo: (groupConfigs, context, options) => {
  2020. /**
  2021. * @param {string} name name
  2022. */
  2023. const groupByAssetInfoFlag = name => {
  2024. groupConfigs.push({
  2025. getKeys: asset => (asset.info && asset.info[name] ? ["1"] : undefined),
  2026. createGroup: (key, children, assets) => ({
  2027. type: "assets by info",
  2028. info: {
  2029. [name]: Boolean(key)
  2030. },
  2031. children,
  2032. ...assetGroup(children, assets)
  2033. })
  2034. });
  2035. };
  2036. groupByAssetInfoFlag("immutable");
  2037. groupByAssetInfoFlag("development");
  2038. groupByAssetInfoFlag("hotModuleReplacement");
  2039. },
  2040. groupAssetsByChunk: (groupConfigs, context, options) => {
  2041. /**
  2042. * @param {keyof KnownStatsAsset} name name
  2043. */
  2044. const groupByNames = name => {
  2045. groupConfigs.push({
  2046. getKeys: asset => /** @type {string[]} */ (asset[name]),
  2047. createGroup: (key, children, assets) => ({
  2048. type: "assets by chunk",
  2049. [name]: [key],
  2050. children,
  2051. ...assetGroup(children, assets)
  2052. })
  2053. });
  2054. };
  2055. groupByNames("chunkNames");
  2056. groupByNames("auxiliaryChunkNames");
  2057. groupByNames("chunkIdHints");
  2058. groupByNames("auxiliaryChunkIdHints");
  2059. },
  2060. excludeAssets: (groupConfigs, context, { excludeAssets }) => {
  2061. groupConfigs.push({
  2062. getKeys: asset => {
  2063. const ident = asset.name;
  2064. const excluded = excludeAssets.some(fn => fn(ident, asset));
  2065. if (excluded) return ["excluded"];
  2066. },
  2067. getOptions: () => ({
  2068. groupChildren: false,
  2069. force: true
  2070. }),
  2071. createGroup: (key, children, assets) => ({
  2072. type: "hidden assets",
  2073. filteredChildren: assets.length,
  2074. ...assetGroup(children, assets)
  2075. })
  2076. });
  2077. }
  2078. };
  2079. /** @typedef {Record<string, (groupConfigs: GroupConfig<KnownStatsModule, TODO>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} ModulesGroupers */
  2080. /** @type {(type: "module" | "chunk" | "root-of-chunk" | "nested") => ModulesGroupers} */
  2081. const MODULES_GROUPERS = type => ({
  2082. _: (groupConfigs, context, options) => {
  2083. /**
  2084. * @param {keyof KnownStatsModule} name name
  2085. * @param {string} type type
  2086. * @param {boolean=} exclude need exclude?
  2087. */
  2088. const groupByFlag = (name, type, exclude) => {
  2089. groupConfigs.push({
  2090. getKeys: module => (module[name] ? ["1"] : undefined),
  2091. getOptions: () => ({
  2092. groupChildren: !exclude,
  2093. force: exclude
  2094. }),
  2095. createGroup: (key, children, modules) => ({
  2096. type,
  2097. [name]: Boolean(key),
  2098. ...(exclude ? { filteredChildren: modules.length } : { children }),
  2099. ...moduleGroup(children, modules)
  2100. })
  2101. });
  2102. };
  2103. const {
  2104. groupModulesByCacheStatus,
  2105. groupModulesByLayer,
  2106. groupModulesByAttributes,
  2107. groupModulesByType,
  2108. groupModulesByPath,
  2109. groupModulesByExtension
  2110. } = options;
  2111. if (groupModulesByAttributes) {
  2112. groupByFlag("errors", "modules with errors");
  2113. groupByFlag("warnings", "modules with warnings");
  2114. groupByFlag("assets", "modules with assets");
  2115. groupByFlag("optional", "optional modules");
  2116. }
  2117. if (groupModulesByCacheStatus) {
  2118. groupByFlag("cacheable", "cacheable modules");
  2119. groupByFlag("built", "built modules");
  2120. groupByFlag("codeGenerated", "code generated modules");
  2121. }
  2122. if (groupModulesByCacheStatus || !options.cachedModules) {
  2123. groupByFlag("cached", "cached modules", !options.cachedModules);
  2124. }
  2125. if (groupModulesByAttributes || !options.orphanModules) {
  2126. groupByFlag("orphan", "orphan modules", !options.orphanModules);
  2127. }
  2128. if (groupModulesByAttributes || !options.dependentModules) {
  2129. groupByFlag("dependent", "dependent modules", !options.dependentModules);
  2130. }
  2131. if (groupModulesByType || !options.runtimeModules) {
  2132. groupConfigs.push({
  2133. getKeys: module => {
  2134. if (!module.moduleType) return;
  2135. if (groupModulesByType) {
  2136. return [module.moduleType.split("/", 1)[0]];
  2137. } else if (module.moduleType === WEBPACK_MODULE_TYPE_RUNTIME) {
  2138. return [WEBPACK_MODULE_TYPE_RUNTIME];
  2139. }
  2140. },
  2141. getOptions: key => {
  2142. const exclude =
  2143. key === WEBPACK_MODULE_TYPE_RUNTIME && !options.runtimeModules;
  2144. return {
  2145. groupChildren: !exclude,
  2146. force: exclude
  2147. };
  2148. },
  2149. createGroup: (key, children, modules) => {
  2150. const exclude =
  2151. key === WEBPACK_MODULE_TYPE_RUNTIME && !options.runtimeModules;
  2152. return {
  2153. type: `${key} modules`,
  2154. moduleType: key,
  2155. ...(exclude ? { filteredChildren: modules.length } : { children }),
  2156. ...moduleGroup(children, modules)
  2157. };
  2158. }
  2159. });
  2160. }
  2161. if (groupModulesByLayer) {
  2162. groupConfigs.push({
  2163. getKeys: module => /** @type {string[]} */ ([module.layer]),
  2164. createGroup: (key, children, modules) => ({
  2165. type: "modules by layer",
  2166. layer: key,
  2167. children,
  2168. ...moduleGroup(children, modules)
  2169. })
  2170. });
  2171. }
  2172. if (groupModulesByPath || groupModulesByExtension) {
  2173. groupConfigs.push({
  2174. getKeys: module => {
  2175. if (!module.name) return;
  2176. const resource = parseResource(
  2177. /** @type {string} */ (module.name.split("!").pop())
  2178. ).path;
  2179. const dataUrl = /^data:[^,;]+/.exec(resource);
  2180. if (dataUrl) return [dataUrl[0]];
  2181. const extensionMatch =
  2182. groupModulesByExtension && GROUP_EXTENSION_REGEXP.exec(resource);
  2183. const extension = extensionMatch ? extensionMatch[1] : "";
  2184. const pathMatch =
  2185. groupModulesByPath && GROUP_PATH_REGEXP.exec(resource);
  2186. const path = pathMatch ? pathMatch[1].split(/[/\\]/) : [];
  2187. const keys = [];
  2188. if (groupModulesByPath) {
  2189. if (extension)
  2190. keys.push(
  2191. path.length
  2192. ? `${path.join("/")}/*${extension}`
  2193. : `*${extension}`
  2194. );
  2195. while (path.length > 0) {
  2196. keys.push(`${path.join("/")}/`);
  2197. path.pop();
  2198. }
  2199. } else if (extension) {
  2200. keys.push(`*${extension}`);
  2201. }
  2202. return keys;
  2203. },
  2204. createGroup: (key, children, modules) => {
  2205. const isDataUrl = key.startsWith("data:");
  2206. return {
  2207. type: isDataUrl
  2208. ? "modules by mime type"
  2209. : groupModulesByPath
  2210. ? "modules by path"
  2211. : "modules by extension",
  2212. name: isDataUrl ? key.slice(/* 'data:'.length */ 5) : key,
  2213. children,
  2214. ...moduleGroup(children, modules)
  2215. };
  2216. }
  2217. });
  2218. }
  2219. },
  2220. excludeModules: (groupConfigs, context, { excludeModules }) => {
  2221. groupConfigs.push({
  2222. getKeys: module => {
  2223. const name = module.name;
  2224. if (name) {
  2225. const excluded = excludeModules.some(fn => fn(name, module, type));
  2226. if (excluded) return ["1"];
  2227. }
  2228. },
  2229. getOptions: () => ({
  2230. groupChildren: false,
  2231. force: true
  2232. }),
  2233. createGroup: (key, children, modules) => ({
  2234. type: "hidden modules",
  2235. filteredChildren: children.length,
  2236. ...moduleGroup(children, modules)
  2237. })
  2238. });
  2239. }
  2240. });
  2241. /** @typedef {Record<string, (groupConfigs: GroupConfig<KnownStatsModuleReason, TODO>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} ModuleReasonsGroupers */
  2242. /** @type {ModuleReasonsGroupers} */
  2243. const MODULE_REASONS_GROUPERS = {
  2244. groupReasonsByOrigin: groupConfigs => {
  2245. groupConfigs.push({
  2246. getKeys: reason => /** @type {string[]} */ ([reason.module]),
  2247. createGroup: (key, children, reasons) => ({
  2248. type: "from origin",
  2249. module: key,
  2250. children,
  2251. ...reasonGroup(children, reasons)
  2252. })
  2253. });
  2254. }
  2255. };
  2256. /** @type {Record<string, AssetsGroupers | ModulesGroupers | ModuleReasonsGroupers>} */
  2257. const RESULT_GROUPERS = {
  2258. "compilation.assets": ASSETS_GROUPERS,
  2259. "asset.related": ASSETS_GROUPERS,
  2260. "compilation.modules": MODULES_GROUPERS("module"),
  2261. "chunk.modules": MODULES_GROUPERS("chunk"),
  2262. "chunk.rootModules": MODULES_GROUPERS("root-of-chunk"),
  2263. "module.modules": MODULES_GROUPERS("nested"),
  2264. "module.reasons": MODULE_REASONS_GROUPERS
  2265. };
  2266. // remove a prefixed "!" that can be specified to reverse sort order
  2267. /**
  2268. * @param {string} field a field name
  2269. * @returns {field} normalized field
  2270. */
  2271. const normalizeFieldKey = field => {
  2272. if (field[0] === "!") {
  2273. return field.slice(1);
  2274. }
  2275. return field;
  2276. };
  2277. // if a field is prefixed by a "!" reverse sort order
  2278. /**
  2279. * @param {string} field a field name
  2280. * @returns {boolean} result
  2281. */
  2282. const sortOrderRegular = field => {
  2283. if (field[0] === "!") {
  2284. return false;
  2285. }
  2286. return true;
  2287. };
  2288. /**
  2289. * @template T
  2290. * @param {string | false} field field name
  2291. * @returns {(a: T, b: T) => 0 | 1 | -1} comparators
  2292. */
  2293. const sortByField = field => {
  2294. if (!field) {
  2295. /**
  2296. * @param {T} a first
  2297. * @param {T} b second
  2298. * @returns {-1 | 0 | 1} zero
  2299. */
  2300. const noSort = (a, b) => 0;
  2301. return noSort;
  2302. }
  2303. const fieldKey = normalizeFieldKey(field);
  2304. let sortFn = compareSelect(m => m[fieldKey], compareIds);
  2305. // if a field is prefixed with a "!" the sort is reversed!
  2306. const sortIsRegular = sortOrderRegular(field);
  2307. if (!sortIsRegular) {
  2308. const oldSortFn = sortFn;
  2309. sortFn = (a, b) => oldSortFn(b, a);
  2310. }
  2311. return sortFn;
  2312. };
  2313. /** @type {Record<string, (comparators: Comparator<TODO>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>} */
  2314. const ASSET_SORTERS = {
  2315. assetsSort: (comparators, context, { assetsSort }) => {
  2316. comparators.push(sortByField(assetsSort));
  2317. },
  2318. _: comparators => {
  2319. comparators.push(compareSelect(a => a.name, compareIds));
  2320. }
  2321. };
  2322. /** @type {Record<string, Record<string, (comparators: Comparator<TODO>[], context: StatsFactoryContext, options: NormalizedStatsOptions) => void>>} */
  2323. const RESULT_SORTERS = {
  2324. "compilation.chunks": {
  2325. chunksSort: (comparators, context, { chunksSort }) => {
  2326. comparators.push(sortByField(chunksSort));
  2327. }
  2328. },
  2329. "compilation.modules": {
  2330. modulesSort: (comparators, context, { modulesSort }) => {
  2331. comparators.push(sortByField(modulesSort));
  2332. }
  2333. },
  2334. "chunk.modules": {
  2335. chunkModulesSort: (comparators, context, { chunkModulesSort }) => {
  2336. comparators.push(sortByField(chunkModulesSort));
  2337. }
  2338. },
  2339. "module.modules": {
  2340. nestedModulesSort: (comparators, context, { nestedModulesSort }) => {
  2341. comparators.push(sortByField(nestedModulesSort));
  2342. }
  2343. },
  2344. "compilation.assets": ASSET_SORTERS,
  2345. "asset.related": ASSET_SORTERS
  2346. };
  2347. /**
  2348. * @template T
  2349. * @param {Record<string, Record<string, T>>} config the config see above
  2350. * @param {NormalizedStatsOptions} options stats options
  2351. * @param {(hookFor: string, fn: T) => void} fn handler function called for every active line in config
  2352. * @returns {void}
  2353. */
  2354. const iterateConfig = (config, options, fn) => {
  2355. for (const hookFor of Object.keys(config)) {
  2356. const subConfig = config[hookFor];
  2357. for (const option of Object.keys(subConfig)) {
  2358. if (option !== "_") {
  2359. if (option.startsWith("!")) {
  2360. if (options[option.slice(1)]) continue;
  2361. } else {
  2362. const value = options[option];
  2363. if (
  2364. value === false ||
  2365. value === undefined ||
  2366. (Array.isArray(value) && value.length === 0)
  2367. )
  2368. continue;
  2369. }
  2370. }
  2371. fn(hookFor, subConfig[option]);
  2372. }
  2373. }
  2374. };
  2375. /** @type {Record<string, string>} */
  2376. const ITEM_NAMES = {
  2377. "compilation.children[]": "compilation",
  2378. "compilation.modules[]": "module",
  2379. "compilation.entrypoints[]": "chunkGroup",
  2380. "compilation.namedChunkGroups[]": "chunkGroup",
  2381. "compilation.errors[]": "error",
  2382. "compilation.warnings[]": "warning",
  2383. "chunk.modules[]": "module",
  2384. "chunk.rootModules[]": "module",
  2385. "chunk.origins[]": "chunkOrigin",
  2386. "compilation.chunks[]": "chunk",
  2387. "compilation.assets[]": "asset",
  2388. "asset.related[]": "asset",
  2389. "module.issuerPath[]": "moduleIssuer",
  2390. "module.reasons[]": "moduleReason",
  2391. "module.modules[]": "module",
  2392. "module.children[]": "module",
  2393. "moduleTrace[]": "moduleTraceItem",
  2394. "moduleTraceItem.dependencies[]": "moduleTraceDependency"
  2395. };
  2396. /**
  2397. * @template T
  2398. * @typedef {{ name: T }} NamedObject
  2399. */
  2400. /**
  2401. * @template {{ name: string }} T
  2402. * @param {T[]} items items to be merged
  2403. * @returns {NamedObject<T>} an object
  2404. */
  2405. const mergeToObject = items => {
  2406. const obj = Object.create(null);
  2407. for (const item of items) {
  2408. obj[item.name] = item;
  2409. }
  2410. return obj;
  2411. };
  2412. /**
  2413. * @template {{ name: string }} T
  2414. * @type {Record<string, (items: T[]) => NamedObject<T>>}
  2415. */
  2416. const MERGER = {
  2417. "compilation.entrypoints": mergeToObject,
  2418. "compilation.namedChunkGroups": mergeToObject
  2419. };
  2420. class DefaultStatsFactoryPlugin {
  2421. /**
  2422. * Apply the plugin
  2423. * @param {Compiler} compiler the compiler instance
  2424. * @returns {void}
  2425. */
  2426. apply(compiler) {
  2427. compiler.hooks.compilation.tap("DefaultStatsFactoryPlugin", compilation => {
  2428. compilation.hooks.statsFactory.tap(
  2429. "DefaultStatsFactoryPlugin",
  2430. /**
  2431. * @param {StatsFactory} stats stats factory
  2432. * @param {NormalizedStatsOptions} options stats options
  2433. */
  2434. (stats, options) => {
  2435. iterateConfig(
  2436. /** @type {TODO} */
  2437. (SIMPLE_EXTRACTORS),
  2438. options,
  2439. (hookFor, fn) => {
  2440. stats.hooks.extract
  2441. .for(hookFor)
  2442. .tap("DefaultStatsFactoryPlugin", (obj, data, ctx) =>
  2443. fn(obj, data, ctx, options, stats)
  2444. );
  2445. }
  2446. );
  2447. iterateConfig(FILTER, options, (hookFor, fn) => {
  2448. stats.hooks.filter
  2449. .for(hookFor)
  2450. .tap("DefaultStatsFactoryPlugin", (item, ctx, idx, i) =>
  2451. fn(item, ctx, options, idx, i)
  2452. );
  2453. });
  2454. iterateConfig(FILTER_RESULTS, options, (hookFor, fn) => {
  2455. stats.hooks.filterResults
  2456. .for(hookFor)
  2457. .tap("DefaultStatsFactoryPlugin", (item, ctx, idx, i) =>
  2458. fn(item, ctx, options, idx, i)
  2459. );
  2460. });
  2461. iterateConfig(SORTERS, options, (hookFor, fn) => {
  2462. stats.hooks.sort
  2463. .for(hookFor)
  2464. .tap("DefaultStatsFactoryPlugin", (comparators, ctx) =>
  2465. fn(comparators, ctx, options)
  2466. );
  2467. });
  2468. iterateConfig(RESULT_SORTERS, options, (hookFor, fn) => {
  2469. stats.hooks.sortResults
  2470. .for(hookFor)
  2471. .tap("DefaultStatsFactoryPlugin", (comparators, ctx) =>
  2472. fn(comparators, ctx, options)
  2473. );
  2474. });
  2475. iterateConfig(
  2476. /** @type {TODO} */
  2477. (RESULT_GROUPERS),
  2478. options,
  2479. (hookFor, fn) => {
  2480. stats.hooks.groupResults
  2481. .for(hookFor)
  2482. .tap("DefaultStatsFactoryPlugin", (groupConfigs, ctx) =>
  2483. fn(groupConfigs, ctx, options)
  2484. );
  2485. }
  2486. );
  2487. for (const key of Object.keys(ITEM_NAMES)) {
  2488. const itemName = ITEM_NAMES[key];
  2489. stats.hooks.getItemName
  2490. .for(key)
  2491. .tap("DefaultStatsFactoryPlugin", () => itemName);
  2492. }
  2493. for (const key of Object.keys(MERGER)) {
  2494. const merger = MERGER[key];
  2495. stats.hooks.merge.for(key).tap("DefaultStatsFactoryPlugin", merger);
  2496. }
  2497. if (options.children) {
  2498. if (Array.isArray(options.children)) {
  2499. stats.hooks.getItemFactory
  2500. .for("compilation.children[].compilation")
  2501. .tap(
  2502. "DefaultStatsFactoryPlugin",
  2503. /**
  2504. * @param {Compilation} comp compilation
  2505. * @param {StatsFactoryContext} options options
  2506. * @returns {StatsFactory | undefined} stats factory
  2507. */
  2508. (comp, { _index: idx }) => {
  2509. const children =
  2510. /** @type {TODO} */
  2511. (options.children);
  2512. if (idx < children.length) {
  2513. return compilation.createStatsFactory(
  2514. compilation.createStatsOptions(children[idx])
  2515. );
  2516. }
  2517. }
  2518. );
  2519. } else if (options.children !== true) {
  2520. const childFactory = compilation.createStatsFactory(
  2521. compilation.createStatsOptions(options.children)
  2522. );
  2523. stats.hooks.getItemFactory
  2524. .for("compilation.children[].compilation")
  2525. .tap("DefaultStatsFactoryPlugin", () => childFactory);
  2526. }
  2527. }
  2528. }
  2529. );
  2530. });
  2531. }
  2532. }
  2533. module.exports = DefaultStatsFactoryPlugin;