@@ -3,117 +3,36 @@ import { formatBytes } from '@code-pushup/utils';
33import type { GroupingRule } from '../../types.js' ;
44import type { UnifiedStats } from '../../unify/unified-stats.types.js' ;
55import {
6- findMatchingRule ,
7- generateGroupKey ,
8- matchesAnyPattern ,
9- } from './utils/match-pattern.js' ;
10- import { type GroupData , createGroupManager } from './utils/table-utils .js' ;
6+ type GroupData ,
7+ createGroupManager ,
8+ findOrCreateGroupFromRule ,
9+ processForTable ,
10+ } from './utils/grouping-engine .js' ;
1111
1212const DEFAULT_GROUP_NAME = 'Group' ;
1313const REST_GROUP_NAME = 'Rest' ;
1414
1515export type InsightsConfig = GroupingRule [ ] ;
1616
17- const globalRuleMatchCache = new Map <
18- string ,
19- { ruleIndex : number ; groupKey : string } | null
20- > ( ) ;
21-
22- interface CompiledRule {
23- rule : GroupingRule ;
24- matcher : ( path : string ) => boolean ;
25- groupKeyCache : Map < string , string > ;
26- ruleIndex : number ;
27- }
28-
29- export function clearRuleMatchCache ( ) : void {
30- globalRuleMatchCache . clear ( ) ;
31- }
32-
33- function compileGroupingRules ( rules : GroupingRule [ ] ) : CompiledRule [ ] {
34- return rules . map ( ( rule , ruleIndex ) => {
35- const { patterns } = rule ;
36-
37- const matcher = ( filePath : string ) : boolean => {
38- return matchesAnyPattern ( filePath , patterns , {
39- matchBase : true ,
40- normalizeRelativePaths : true ,
41- } ) ;
42- } ;
43-
44- return {
45- rule,
46- matcher,
47- groupKeyCache : new Map < string , string > ( ) ,
48- ruleIndex,
49- } ;
50- } ) ;
51- }
52-
53- function findMatchingCompiledRule (
54- filePath : string ,
55- compiledRules : CompiledRule [ ] ,
56- ) : CompiledRule | null {
57- const cached = globalRuleMatchCache . get ( filePath ) ;
58- if ( cached !== undefined ) {
59- return cached ? compiledRules [ cached . ruleIndex ] || null : null ;
60- }
61-
62- // Process rules in reverse order to match tree logic precedence
63- // More specific rules (later in array) take precedence over general ones
64- for ( let i = compiledRules . length - 1 ; i >= 0 ; i -- ) {
65- const compiledRule = compiledRules [ i ] ;
66- if ( compiledRule && compiledRule . matcher ( filePath ) ) {
67- globalRuleMatchCache . set ( filePath , {
68- ruleIndex : compiledRule . ruleIndex ,
69- groupKey : '' ,
70- } ) ;
71- return compiledRule ;
72- }
73- }
74-
75- globalRuleMatchCache . set ( filePath , null ) ;
76- return null ;
77- }
78-
79- function getCachedGroupKey (
80- filePath : string ,
81- compiledRule : CompiledRule ,
82- preferRuleTitle : boolean = false ,
83- ) : string {
84- const globalCached = globalRuleMatchCache . get ( filePath ) ;
85- if ( globalCached && globalCached . groupKey ) {
86- return globalCached . groupKey ;
87- }
88-
89- let groupKey = compiledRule . groupKeyCache . get ( filePath ) ;
90- if ( ! groupKey ) {
91- groupKey = generateGroupKey ( filePath , compiledRule . rule , preferRuleTitle ) ;
92- compiledRule . groupKeyCache . set ( filePath , groupKey ) ;
93-
94- if ( globalCached ) {
95- globalCached . groupKey = groupKey ;
96- }
97- }
98- return groupKey ;
99- }
100-
101- export function formatEntryPoint ( title : string , icon ?: string ) : string {
102- return icon ? `${ icon } ${ title } ` : title ;
103- }
104-
17+ /**
18+ * Simplified aggregation using direct functions. Simple table grouping without engine complexity.
19+ */
10520export function aggregateAndSortGroups (
10621 statsSlice : UnifiedStats ,
10722 insights : InsightsConfig ,
108- ) : { groups : GroupData [ ] ; restGroup : Omit < GroupData , 'icon' > } {
23+ ) : { groups : GroupData [ ] ; restGroup : { title : string ; bytes : number } } {
10924 const groupingRules = insights || [ ] ;
110-
111- const compiledRules = compileGroupingRules ( groupingRules ) ;
11225 const groupManager = createGroupManager < GroupData > ( ) ;
11326
27+ // Pre-create groups
11428 for ( const rule of groupingRules ) {
11529 const effectiveTitle = rule . title || DEFAULT_GROUP_NAME ;
116- groupManager . findOrCreateGroup ( effectiveTitle , rule , effectiveTitle ) ;
30+ findOrCreateGroupFromRule (
31+ groupManager ,
32+ effectiveTitle ,
33+ rule ,
34+ effectiveTitle ,
35+ ) ;
11736 }
11837
11938 const remainingBytesInChunks : Record < string , number > = { } ;
@@ -123,6 +42,7 @@ export function aggregateAndSortGroups(
12342 remainingBytesInChunks [ key ] = bytes ;
12443 }
12544
45+ // Process inputs with simple functions
12646 for ( const [ outputKey , output ] of outputEntries ) {
12747 if ( ! output . inputs ) {
12848 continue ;
@@ -134,109 +54,106 @@ export function aggregateAndSortGroups(
13454 continue ;
13555 }
13656
137- const matchingCompiledRule = findMatchingCompiledRule (
57+ // Use simple function for rule matching and key generation
58+ const { rule, groupKey } = processForTable (
13859 inputPath ,
139- compiledRules ,
60+ groupingRules ,
61+ true ,
14062 ) ;
141- if ( matchingCompiledRule ) {
142- // For input files, prefer rule title to support explicit titles like "Theme Park Package"
143- const groupKey = getCachedGroupKey (
144- inputPath ,
145- matchingCompiledRule ,
146- true ,
147- ) ;
148- const group = groupManager . findOrCreateGroup (
63+ if ( rule && groupKey ) {
64+ const group = findOrCreateGroupFromRule (
65+ groupManager ,
14966 groupKey ,
150- matchingCompiledRule . rule ,
151- matchingCompiledRule . rule . title || groupKey ,
67+ rule ,
68+ rule . title || groupKey ,
15269 ) ;
15370
154- group . totalBytes += input . bytes ;
71+ group . bytes += input . bytes ;
15572 remainingBytesInChunks [ outputKey ] =
15673 ( remainingBytesInChunks [ outputKey ] || 0 ) - input . bytes ;
15774 }
15875 }
15976 }
16077
78+ // Process outputs with simple functions
16179 for ( const [ outputKey ] of outputEntries ) {
16280 const remainingBytes = remainingBytesInChunks [ outputKey ] ;
16381 if ( remainingBytes == null || remainingBytes <= 0 ) {
16482 continue ;
16583 }
16684
167- const matchingCompiledRule = findMatchingCompiledRule (
168- outputKey ,
169- compiledRules ,
170- ) ;
171- if ( matchingCompiledRule ) {
172- const groupKey = getCachedGroupKey (
173- outputKey ,
174- matchingCompiledRule ,
175- false ,
176- ) ;
177- const group = groupManager . findOrCreateGroup (
85+ const { rule, groupKey } = processForTable ( outputKey , groupingRules , true ) ;
86+ if ( rule && groupKey ) {
87+ const group = findOrCreateGroupFromRule (
88+ groupManager ,
17889 groupKey ,
179- matchingCompiledRule . rule ,
180- matchingCompiledRule . rule . title || groupKey ,
90+ rule ,
91+ rule . title || groupKey ,
18192 ) ;
18293
183- group . totalBytes += remainingBytes ;
94+ group . bytes += remainingBytes ;
18495 remainingBytesInChunks [ outputKey ] = 0 ;
18596 }
18697 }
18798
18899 const restGroup = {
189- totalBytes : Object . values ( remainingBytesInChunks ) . reduce (
100+ bytes : Object . values ( remainingBytesInChunks ) . reduce (
190101 ( acc , bytes ) => acc + bytes ,
191102 0 ,
192103 ) ,
193104 title : REST_GROUP_NAME ,
194105 } ;
195106
196107 const groups = groupManager . getGroupsWithData ( ) ;
197- groups . sort ( ( a , b ) => b . totalBytes - a . totalBytes ) ;
108+ groups . sort ( ( a , b ) => b . bytes - a . bytes ) ;
198109
199110 return { groups, restGroup } ;
200111}
201112
202- export function formatGroupsAsTable ( {
203- groups,
204- restGroup,
205- } : {
206- groups : GroupData [ ] ;
207- restGroup : Omit < GroupData , 'icon' > ;
208- } ) : Table {
209- const tableRows : string [ ] [ ] = [ ] ;
210- for ( const group of groups ) {
211- const entryPoint = formatEntryPoint ( group . title , group . icon ) ;
212- const size = formatBytes ( group . totalBytes ) ;
113+ /**
114+ * Transforms aggregated group data into table format. Creates table rows from group statistics.
115+ */
116+ export function createTable (
117+ groups : GroupData [ ] ,
118+ restGroup : { title : string ; bytes : number } ,
119+ ) : Table {
120+ const rows : { group : string ; modules : string ; size : string } [ ] = [ ] ;
213121
214- tableRows . push ( [ entryPoint , size ] ) ;
122+ for ( const group of groups ) {
123+ if ( group . bytes > 0 ) {
124+ rows . push ( {
125+ group : `${ group . icon || '📁' } ${ group . title } ` ,
126+ modules : group . sources . toString ( ) ,
127+ size : formatBytes ( group . bytes ) ,
128+ } ) ;
129+ }
215130 }
216131
217- if ( restGroup . totalBytes > 0 ) {
218- const entryPoint = formatEntryPoint ( restGroup . title ) ;
219- const size = formatBytes ( restGroup . totalBytes ) ;
220-
221- tableRows . push ( [ entryPoint , size ] ) ;
132+ if ( restGroup . bytes > 0 ) {
133+ rows . push ( {
134+ group : '📄 Rest' ,
135+ modules : '-' ,
136+ size : formatBytes ( restGroup . bytes ) ,
137+ } ) ;
222138 }
223139
224140 return {
225141 columns : [
226142 { key : 'group' , label : 'Group' , align : 'left' } ,
227- { key : 'size' , label : 'Size' , align : 'center' } ,
143+ { key : 'modules' , label : 'Modules' , align : 'right' } ,
144+ { key : 'size' , label : 'Size' , align : 'right' } ,
228145 ] ,
229- rows : tableRows . map ( ( [ group = '' , size = '' ] ) => ( {
230- group,
231- size,
232- } ) ) ,
146+ rows,
233147 } ;
234148}
235149
150+ /**
151+ * Creates insights table from stats and grouping rules. Combines aggregation and table formatting.
152+ */
236153export function createInsightsTable (
237154 statsSlice : UnifiedStats ,
238- insights : GroupingRule [ ] ,
155+ insights : InsightsConfig ,
239156) : Table {
240157 const { groups, restGroup } = aggregateAndSortGroups ( statsSlice , insights ) ;
241- return formatGroupsAsTable ( { groups, restGroup } ) ;
158+ return createTable ( groups , restGroup ) ;
242159}
0 commit comments