1
1
import fs from "node:fs/promises" ;
2
2
import path from "node:path" ;
3
3
4
+ export interface FileEntry {
5
+ filePath : string ;
6
+ content : string ;
7
+ }
8
+
4
9
/**
5
10
* Checks whether the given file contains Git merge conflict markers.
6
11
*
7
- * @param filePath - Absolute path to the file .
12
+ * @param content - File content to check .
8
13
* @returns `true` if conflict markers exist, otherwise `false`.
9
14
*/
10
- const hasConflict = async ( filePath : string ) : Promise < boolean > => {
11
- try {
12
- const content = await fs . readFile ( filePath , "utf8" ) ;
13
- return (
14
- content . includes ( "<<<<<<<" ) && content . includes ( "=======" ) && content . includes ( ">>>>>>>" )
15
- ) ;
16
- } catch {
17
- /* v8 ignore next 2 - If file cannot be read (permissions, etc.), treat as non-conflicted */
18
- return false ;
19
- }
15
+ const hasConflict = ( content : string ) : boolean => {
16
+ return content . includes ( "<<<<<<<" ) && content . includes ( "=======" ) && content . includes ( ">>>>>>>" ) ;
20
17
} ;
21
18
22
19
export interface CollectFilesOptions {
@@ -37,16 +34,15 @@ export interface CollectFilesOptions {
37
34
* Recursively collects files that match the provided `fileFilter`.
38
35
*
39
36
* - By default, only conflicted files are returned.
40
- * - If `includeNonConflicted` is enabled, matching files are always included
41
- * (conflict check is skipped).
37
+ * - If `includeNonConflicted` is enabled, matching files are always included.
42
38
*
43
39
* @param options - Collection options, including `fileFilter` and traversal root.
44
- * @returns A promise that resolves with an array of matching file paths .
40
+ * @returns A promise that resolves with an array of `{ filePath, content }` .
45
41
*/
46
- export const collectFiles = async ( options : CollectFilesOptions ) : Promise < string [ ] > => {
42
+ export const collectFiles = async ( options : CollectFilesOptions ) : Promise < FileEntry [ ] > => {
47
43
const { root = process . cwd ( ) , fileFilter, includeNonConflicted = false } = options ;
48
44
49
- const allFiles : string [ ] = [ ] ;
45
+ const collected : FileEntry [ ] = [ ] ;
50
46
51
47
/**
52
48
* Recursively traverses a directory, checking each file against
@@ -64,17 +60,21 @@ export const collectFiles = async (options: CollectFilesOptions): Promise<string
64
60
/* v8 ignore next */
65
61
await walk ( fullPath ) ;
66
62
} else if ( fileFilter ( fullPath ) ) {
67
- if ( includeNonConflicted ) {
68
- allFiles . push ( fullPath ) ;
69
- } else if ( await hasConflict ( fullPath ) ) {
70
- allFiles . push ( fullPath ) ;
71
- } else {
72
- console . info ( `Skipped (no conflicts): ${ fullPath } ` ) ;
63
+ try {
64
+ const content = await fs . readFile ( fullPath , "utf8" ) ;
65
+
66
+ if ( includeNonConflicted || hasConflict ( content ) ) {
67
+ collected . push ( { filePath : fullPath , content } ) ;
68
+ } else {
69
+ console . info ( `Skipped (no conflicts): ${ fullPath } ` ) ;
70
+ }
71
+ } catch {
72
+ console . warn ( `Skipped (unreadable): ${ fullPath } ` ) ;
73
73
}
74
74
}
75
75
}
76
76
} ;
77
77
78
78
await walk ( root ) ;
79
- return allFiles ;
79
+ return collected ;
80
80
} ;
0 commit comments