@@ -10,16 +10,21 @@ export class GitAnalyzer {
1010
1111 async getCommitInfo ( commitHash : string ) : Promise < CommitInfo > {
1212 try {
13- const [ commit , diff ] = await Promise . all ( [
14- this . git . show ( [ commitHash , '--format=%H|%s|%an|%ad' , '--date=iso' ] ) ,
13+ const [ commit , diff , fullDiff ] = await Promise . all ( [
14+ this . git . show ( [ commitHash , '--format=%H|%s|%an|%ad' , '--date=iso' , '--no-patch' ] ) ,
1515 this . git . show ( [ commitHash , '--stat' , '--name-status' ] ) ,
16+ this . git . show ( [ commitHash ] ) ,
1617 ] ) ;
1718
1819 const [ hash , message , author , dateStr ] = commit . trim ( ) . split ( '|' ) ;
19- const date = new Date ( dateStr ) ;
20+ // Parse date string - handle timezone offset by removing space before timezone
21+ const cleanDateStr = dateStr . replace ( " -" , "-" ) . replace ( " +" , "+" ) ;
22+ const date = new Date ( cleanDateStr ) ;
2023
2124 const files = this . parseChangedFiles ( diff ) ;
22- const fullDiff = await this . git . show ( [ commitHash ] ) ;
25+
26+ // Calculate line counts from the full diff
27+ this . calculateLineCounts ( files , fullDiff ) ;
2328
2429 return {
2530 hash : hash . trim ( ) ,
@@ -69,25 +74,22 @@ export class GitAnalyzer {
6974 const lines = diffOutput . split ( '\n' ) ;
7075
7176 for ( const line of lines ) {
72- if ( line . includes ( '|' ) ) {
73- const [ statusAndPath , changes ] = line . split ( '|' ) ;
74- const match = statusAndPath . match ( / ^ ( .+ ?) \s + ( .+ ) $ / ) ;
75-
76- if ( match ) {
77- const [ , status , path ] = match ;
78- const changeMatch = changes . match ( / ( \d + ) \s + ( \d + ) / ) ;
79-
80- if ( changeMatch ) {
81- const [ , additions , deletions ] = changeMatch ;
82- files . push ( {
83- path : path . trim ( ) ,
84- status : this . parseFileStatus ( status . trim ( ) ) ,
85- additions : parseInt ( additions , 10 ) ,
86- deletions : parseInt ( deletions , 10 ) ,
87- diff : '' , // Will be populated separately if needed
88- } ) ;
89- }
90- }
77+ // Skip empty lines and commit info lines
78+ if ( ! line . trim ( ) || line . startsWith ( 'commit' ) || line . startsWith ( 'Author' ) || line . startsWith ( 'Date' ) ) {
79+ continue ;
80+ }
81+
82+ // Parse name-status format: "M\tpath/to/file" or "A\tpath/to/file"
83+ const match = line . match ( / ^ ( [ A M D ] ) \t ( .+ ) $ / ) ;
84+ if ( match ) {
85+ const [ , status , path ] = match ;
86+ files . push ( {
87+ path : path . trim ( ) ,
88+ status : this . parseFileStatus ( status . trim ( ) ) ,
89+ additions : 0 , // Will be calculated from diff if needed
90+ deletions : 0 , // Will be calculated from diff if needed
91+ diff : '' , // Will be populated separately if needed
92+ } ) ;
9193 }
9294 }
9395
@@ -103,6 +105,34 @@ export class GitAnalyzer {
103105 return 'modified' ;
104106 }
105107
108+ private calculateLineCounts ( files : ChangedFile [ ] , fullDiff : string ) : void {
109+ const diffSections = fullDiff . split ( 'diff --git' ) ;
110+
111+ for ( const file of files ) {
112+ // Find the diff section for this file
113+ const fileSection = diffSections . find ( section =>
114+ section . includes ( `a/${ file . path } ` ) || section . includes ( `b/${ file . path } ` )
115+ ) ;
116+
117+ if ( fileSection ) {
118+ const lines = fileSection . split ( '\n' ) ;
119+ let additions = 0 ;
120+ let deletions = 0 ;
121+
122+ for ( const line of lines ) {
123+ if ( line . startsWith ( '+' ) && ! line . startsWith ( '+++' ) ) {
124+ additions ++ ;
125+ } else if ( line . startsWith ( '-' ) && ! line . startsWith ( '---' ) ) {
126+ deletions ++ ;
127+ }
128+ }
129+
130+ file . additions = additions ;
131+ file . deletions = deletions ;
132+ }
133+ }
134+ }
135+
106136 async getFileDiff ( commitHash : string , filePath : string ) : Promise < string > {
107137 try {
108138 return await this . git . show ( [ `${ commitHash } :${ filePath } ` ] ) ;
0 commit comments