diff --git a/src/core/file/filePathSort.ts b/src/core/file/filePathSort.ts index 808055d1b..2d6b4c3ed 100644 --- a/src/core/file/filePathSort.ts +++ b/src/core/file/filePathSort.ts @@ -1,10 +1,14 @@ import path from 'node:path'; // Sort paths for general use (not affected by git change count) +// Uses decorate-sort-undecorate to pre-compute path.split() once per path +// instead of O(N log N) repeated splits during comparisons export const sortPaths = (filePaths: string[]): string[] => { - return filePaths.sort((a, b) => { - const partsA = a.split(path.sep); - const partsB = b.split(path.sep); + const decorated = filePaths.map((p) => ({ original: p, parts: p.split(path.sep) })); + + decorated.sort((a, b) => { + const partsA = a.parts; + const partsB = b.parts; for (let i = 0; i < Math.min(partsA.length, partsB.length); i++) { if (partsA[i] !== partsB[i]) { @@ -21,4 +25,6 @@ export const sortPaths = (filePaths: string[]): string[] => { // Sort by path length when all parts are equal return partsA.length - partsB.length; }); + + return decorated.map((d) => d.original); }; diff --git a/tests/core/file/fileSearch.test.ts b/tests/core/file/fileSearch.test.ts index 8e3e123bf..3a6e19828 100644 --- a/tests/core/file/fileSearch.test.ts +++ b/tests/core/file/fileSearch.test.ts @@ -531,19 +531,25 @@ node_modules }, }); + const sep = path.sep; const mockFileStructure = [ - 'root/file1.js', - 'root/another/file3.js', - 'root/subdir/file2.js', - 'root/subdir/ignored.js', + `root${sep}file1.js`, + `root${sep}another${sep}file3.js`, + `root${sep}subdir${sep}file2.js`, + `root${sep}subdir${sep}ignored.js`, ]; vi.mocked(globby).mockResolvedValue(mockFileStructure); const result = await searchFiles('/mock/root', mockConfig); - expect(result.filePaths).toEqual(mockFileStructure); - expect(result.filePaths).toContain('root/subdir/ignored.js'); + expect(result.filePaths).toEqual([ + `root${sep}another${sep}file3.js`, + `root${sep}subdir${sep}file2.js`, + `root${sep}subdir${sep}ignored.js`, + `root${sep}file1.js`, + ]); + expect(result.filePaths).toContain(`root${sep}subdir${sep}ignored.js`); expect(result.emptyDirPaths).toEqual([]); });