@@ -7,14 +7,14 @@ import {
77 type GithubPRComment ,
88 fetchGithubPRWithComments ,
99} from "./github.svelte" ;
10- import { type StructuredPatch , parsePatch } from "diff" ;
10+ import { type StructuredPatch } from "diff" ;
1111import {
1212 ConciseDiffViewCachedState ,
1313 DEFAULT_THEME_DARK ,
1414 DEFAULT_THEME_LIGHT ,
15- hasNonHeaderChanges ,
1615 isNoNewlineAtEofLine ,
1716 parseSinglePatch ,
17+ patchHeaderDiffOnly ,
1818} from "$lib/components/diff/concise-diff-view.svelte" ;
1919import type { BundledTheme } from "shiki" ;
2020import { browser } from "$app/environment" ;
@@ -158,8 +158,8 @@ export type CommonFileDetails = {
158158
159159export type TextFileDetails = CommonFileDetails & {
160160 type : "text" ;
161- patchText : string ;
162- structuredPatch : Promise < StructuredPatch > ;
161+ structuredPatch : StructuredPatch ;
162+ patchHeaderDiffOnly : boolean ;
163163} ;
164164
165165export type ImageFileDetails = CommonFileDetails & {
@@ -168,13 +168,14 @@ export type ImageFileDetails = CommonFileDetails & {
168168} ;
169169
170170export function makeTextDetails ( fromFile : string , toFile : string , status : FileStatus , patchText : string ) : TextFileDetails {
171+ const patch = parseSinglePatch ( patchText ) ;
171172 return {
172173 type : "text" ,
173174 fromFile,
174175 toFile,
175176 status,
176- patchText ,
177- structuredPatch : ( async ( ) => parseSinglePatch ( patchText ) ) ( ) ,
177+ structuredPatch : patch ,
178+ patchHeaderDiffOnly : patchHeaderDiffOnly ( patch ) ,
178179 } ;
179180}
180181
@@ -293,45 +294,6 @@ export function getFileStatusProps(status: FileStatus): FileStatusProps {
293294 }
294295}
295296
296- export function findHeaderChangeOnlyPatches ( fileDetails : FileDetails [ ] ) {
297- const patchStrings = fileDetails . map ( ( details ) => {
298- if ( details . type === "text" ) {
299- return details . patchText ;
300- }
301- return undefined ;
302- } ) ;
303-
304- const result : boolean [ ] = [ ] ;
305-
306- for ( let i = 0 ; i < patchStrings . length ; i ++ ) {
307- const patchString = patchStrings [ i ] ;
308- if ( patchString === undefined || patchString . length === 0 ) {
309- result . push ( false ) ;
310- continue ;
311- }
312- // TODO: Parsing twice is wasteful
313- const patches = parsePatch ( patchString ) ;
314- if ( patches . length !== 1 ) {
315- result . push ( false ) ;
316- continue ;
317- }
318- const patch = patches [ 0 ] ;
319- if ( patch . hunks . length === 0 ) {
320- result . push ( false ) ;
321- continue ;
322- }
323- let onlyHeaderChanges = true ;
324- for ( let j = 0 ; j < patch . hunks . length ; j ++ ) {
325- if ( hasNonHeaderChanges ( patch . hunks [ j ] . lines ) ) {
326- onlyHeaderChanges = false ;
327- }
328- }
329- result . push ( onlyHeaderChanges ) ;
330- }
331-
332- return result ;
333- }
334-
335297export type ViewerStatistics = {
336298 addedLines : number ;
337299 removedLines : number ;
@@ -400,19 +362,22 @@ export class MultiFileDiffViewerState {
400362
401363 readonly fileTreeFilterDebounced = new Debounced ( ( ) => this . fileTreeFilter , 500 ) ;
402364 readonly searchQueryDebounced = new Debounced ( ( ) => this . searchQuery , 500 ) ;
403- readonly stats : Promise < ViewerStatistics > = $derived ( this . countStats ( ) ) ;
365+ readonly stats : ViewerStatistics = $derived ( this . countStats ( ) ) ;
404366 readonly fileTreeRoots : TreeNode < FileTreeNodeData > [ ] = $derived ( makeFileTree ( this . fileDetails ) ) ;
405367 readonly filteredFileDetails : FileDetails [ ] = $derived (
406368 this . fileTreeFilterDebounced . current ? this . fileDetails . filter ( ( f ) => this . filterFile ( f ) ) : this . fileDetails ,
407369 ) ;
408- readonly patchHeaderDiffOnly : boolean [ ] = $derived ( findHeaderChangeOnlyPatches ( this . fileDetails ) ) ;
409370 readonly searchResults : Promise < SearchResults > = $derived ( this . findSearchResults ( ) ) ;
410371
411372 private constructor ( ) {
412373 // Auto-check all patch header diff only diffs
413374 $effect ( ( ) => {
414- for ( let i = 0 ; i < this . patchHeaderDiffOnly . length ; i ++ ) {
415- if ( this . patchHeaderDiffOnly [ i ] && this . checked [ i ] === undefined ) {
375+ for ( let i = 0 ; i < this . fileDetails . length ; i ++ ) {
376+ const details = this . fileDetails [ i ] ;
377+ if ( details . type !== "text" ) {
378+ continue ;
379+ }
380+ if ( details . patchHeaderDiffOnly && this . checked [ i ] === undefined ) {
416381 this . checked [ i ] = true ;
417382 }
418383 }
@@ -718,7 +683,7 @@ export class MultiFileDiffViewerState {
718683 return this . diffMetadata ?. type === "github" && ! ! this . diffMetadata . prNumber ;
719684 }
720685
721- private async countStats ( ) : Promise < ViewerStatistics > {
686+ private countStats ( ) : ViewerStatistics {
722687 let addedLines = 0 ;
723688 let removedLines = 0 ;
724689 const fileAddedLines : number [ ] = [ ] ;
@@ -729,7 +694,7 @@ export class MultiFileDiffViewerState {
729694 if ( details . type !== "text" ) {
730695 continue ;
731696 }
732- const diff = await details . structuredPatch ;
697+ const diff = details . structuredPatch ;
733698
734699 for ( let j = 0 ; j < diff . hunks . length ; j ++ ) {
735700 const hunk = diff . hunks [ j ] ;
0 commit comments