@@ -50,7 +50,8 @@ export interface APIBuilderOptions {
5050export type GenerationReport = {
5151 success : boolean ;
5252 outputDir : string ;
53- filesGenerated : Record < string , string > ;
53+ /** Generated files nested by generator name, then by path: `filesGenerated[generator][path] = content`. */
54+ filesGenerated : Record < string , Record < string , string > > ;
5455 errors : string [ ] ;
5556 warnings : string [ ] ;
5657 duration : number ;
@@ -62,21 +63,67 @@ function countLinesByMatches(text: string): number {
6263 return m ? m . length + 1 : 1 ;
6364}
6465
65- export const prettyReport = ( report : GenerationReport ) : string => {
66+ const formatLoc = ( loc : number ) : string => {
67+ if ( loc >= 10000 ) return `${ Math . round ( loc / 1000 ) } kloc` ;
68+ if ( loc >= 1000 ) return `${ ( loc / 1000 ) . toFixed ( 1 ) } kloc` ;
69+ return `${ loc } loc` ;
70+ } ;
71+
72+ export interface PrettyReportOptions {
73+ /** When a generator produces more than this many files, aggregate them by directory instead of listing each file. */
74+ fileLimit ?: number ;
75+ }
76+
77+ export const prettyReport = ( report : GenerationReport , options : PrettyReportOptions = { } ) : string => {
6678 const { success, filesGenerated, errors, warnings, duration } = report ;
79+ const fileLimit = options . fileLimit ?? 20 ;
6780 const errorsStr = errors . length > 0 ? `Errors: ${ errors . join ( ", " ) } ` : undefined ;
6881 const warningsStr = warnings . length > 0 ? `Warnings: ${ warnings . join ( ", " ) } ` : undefined ;
69- let allLoc = 0 ;
70- const files = Object . entries ( filesGenerated )
71- . map ( ( [ path , content ] ) => {
82+
83+ let totalFiles = 0 ;
84+ let totalLoc = 0 ;
85+
86+ const aggregateByDir = ( files : Record < string , number > ) : { dir : string ; count : number ; loc : number } [ ] => {
87+ const byDir : Record < string , { count : number ; loc : number } > = { } ;
88+ for ( const [ p , loc ] of Object . entries ( files ) ) {
89+ const dir = Path . dirname ( p ) ;
90+ byDir [ dir ] ??= { count : 0 , loc : 0 } ;
91+ byDir [ dir ] . count += 1 ;
92+ byDir [ dir ] . loc += loc ;
93+ }
94+ return Object . entries ( byDir )
95+ . map ( ( [ dir , v ] ) => ( { dir, count : v . count , loc : v . loc } ) )
96+ . sort ( ( a , b ) => a . dir . localeCompare ( b . dir ) ) ;
97+ } ;
98+
99+ const groupStrs = Object . entries ( filesGenerated ) . map ( ( [ name , files ] ) => {
100+ const locByPath : Record < string , number > = { } ;
101+ let groupLoc = 0 ;
102+ for ( const [ path , content ] of Object . entries ( files ) ) {
72103 const loc = countLinesByMatches ( content ) ;
73- allLoc += loc ;
74- return ` - ${ path } (${ loc } loc)` ;
75- } )
76- . join ( "\n" ) ;
104+ locByPath [ path ] = loc ;
105+ groupLoc += loc ;
106+ }
107+ const count = Object . keys ( files ) . length ;
108+ totalFiles += count ;
109+ totalLoc += groupLoc ;
110+
111+ const header = ` ${ name } (${ count } files, ${ formatLoc ( groupLoc ) } ):` ;
112+ if ( count === 0 ) return header ;
113+ if ( count > fileLimit ) {
114+ const dirs = aggregateByDir ( locByPath ) ;
115+ const dirLines = dirs . map ( ( d ) => ` - ${ d . dir } / (${ d . count } files, ${ formatLoc ( d . loc ) } )` ) . join ( "\n" ) ;
116+ return `${ header } \n${ dirLines } ` ;
117+ }
118+ const fileLines = Object . entries ( locByPath )
119+ . map ( ( [ p , loc ] ) => ` - ${ p } (${ loc } loc)` )
120+ . join ( "\n" ) ;
121+ return `${ header } \n${ fileLines } ` ;
122+ } ) ;
123+
77124 return [
78- `Generated files (${ Math . round ( allLoc / 1000 ) } kloc ):` ,
79- files ,
125+ `Generated files (${ totalFiles } files, ${ formatLoc ( totalLoc ) } ):` ,
126+ ... groupStrs ,
80127 errorsStr ,
81128 warningsStr ,
82129 `Duration: ${ Math . round ( duration ) } ms` ,
@@ -447,7 +494,8 @@ export class APIBuilder {
447494
448495 result . success = result . errors . length === 0 ;
449496
450- this . logger . debug ( `Generation completed: ${ result . filesGenerated . length } files` ) ;
497+ const totalFiles = Object . values ( result . filesGenerated ) . reduce ( ( n , f ) => n + Object . keys ( f ) . length , 0 ) ;
498+ this . logger . debug ( `Generation completed: ${ totalFiles } files` ) ;
451499 } catch ( error ) {
452500 this . logger . error ( `Code generation failed: ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
453501 result . errors . push ( error instanceof Error ? error . message : String ( error ) ) ;
@@ -483,8 +531,9 @@ export class APIBuilder {
483531 try {
484532 await gen . writer . generateAsync ( tsIndex ) ;
485533 const fileBuffer : FileBuffer [ ] = gen . writer . writtenFiles ( ) ;
534+ const files = ( result . filesGenerated [ gen . name ] ??= { } ) ;
486535 fileBuffer . forEach ( ( buf ) => {
487- result . filesGenerated [ buf . relPath ] = buf . content ;
536+ files [ buf . relPath ] = buf . content ;
488537 } ) ;
489538 this . logger . info ( `Generating ${ gen . name } finished successfully` ) ;
490539 } catch ( error ) {
0 commit comments