Skip to content

Commit a5dbe91

Browse files
authored
perf(fmt): filter ignored files during traversal (#215)
1 parent fc0678b commit a5dbe91

3 files changed

Lines changed: 33 additions & 18 deletions

File tree

packages/rstack/src/fmt/discoverPaths.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ interface DiscoverFmtPathsOptions {
1818
patterns?: string[];
1919
/** Whether files inside node_modules may be discovered. */
2020
withNodeModules?: boolean;
21-
/** Returns whether a scanned directory can be pruned before traversal. */
22-
isDirectoryIgnored?: (directoryPath: string) => boolean;
21+
/** Returns whether a scanned path can be excluded during traversal. */
22+
isIgnored?: (filePath: string, isDirectory: boolean) => boolean;
2323
}
2424

2525
const isErrnoException = (error: unknown): error is NodeJS.ErrnoException =>
@@ -209,7 +209,7 @@ const createTraversalOptions = (
209209
gitIgnore: GitIgnoreMatcher,
210210
ignoredDirNames: ReadonlySet<string>,
211211
isIncluded?: (filePath: string) => boolean,
212-
isDirectoryIgnored?: (directoryPath: string) => boolean,
212+
isIgnored?: (filePath: string, isDirectory: boolean) => boolean,
213213
) => {
214214
return {
215215
followSymlinks: false,
@@ -221,12 +221,16 @@ const createTraversalOptions = (
221221
}
222222

223223
if (dirent.isDirectory()) {
224-
return gitIgnore.isIgnored(targetPath, true) || isDirectoryIgnored?.(targetPath) === true;
224+
return gitIgnore.isIgnored(targetPath, true) || isIgnored?.(targetPath, true) === true;
225+
}
226+
227+
if (isIncluded !== undefined && !isIncluded(targetPath)) {
228+
return true;
225229
}
226230

227231
return (
232+
isIgnored?.(targetPath, false) === true ||
228233
isBinaryPath(targetPath) ||
229-
(isIncluded !== undefined && !isIncluded(targetPath)) ||
230234
gitIgnore.isIgnored(targetPath, false)
231235
);
232236
},
@@ -352,7 +356,7 @@ const discoverFmtPaths = async ({
352356
cwd,
353357
patterns: inputPatterns,
354358
withNodeModules = false,
355-
isDirectoryIgnored,
359+
isIgnored,
356360
}: DiscoverFmtPathsOptions): Promise<string[]> => {
357361
const patterns = inputPatterns?.length ? inputPatterns : ['.'];
358362
const resolveRelativePath = createRelativePathResolver(cwd);
@@ -385,7 +389,7 @@ const discoverFmtPaths = async ({
385389
}
386390

387391
await gitIgnore.loadThrough(rootPath);
388-
if (gitIgnore.isIgnored(rootPath, true) || isDirectoryIgnored?.(rootPath) === true) {
392+
if (gitIgnore.isIgnored(rootPath, true) || isIgnored?.(rootPath, true) === true) {
389393
return [];
390394
}
391395

@@ -406,7 +410,7 @@ const discoverFmtPaths = async ({
406410
return (
407411
await readdir(
408412
rootPath,
409-
createTraversalOptions(gitIgnore, ignoredDirNames, isIncluded, isDirectoryIgnored),
413+
createTraversalOptions(gitIgnore, ignoredDirNames, isIncluded, isIgnored),
410414
)
411415
).files;
412416
}),

packages/rstack/src/fmt/discovery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const discoverFmtFiles = async ({
2424
cwd,
2525
patterns,
2626
withNodeModules,
27-
isDirectoryIgnored: (directoryPath) => isIgnored(directoryPath, true),
27+
isIgnored,
2828
});
2929
if (candidates.length === 0) {
3030
return [];

packages/rstack/tests/fmt/discoverPaths.test.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,28 +139,39 @@ test('lets explicit files bypass gitignore', async () => {
139139
});
140140
});
141141

142-
test('prunes directories with an external ignore matcher', async () => {
142+
test('applies an external ignore matcher during traversal', async () => {
143143
await withTempProject(async (rootPath) => {
144144
writeProjectFile(rootPath, 'generated/nested/output.ts');
145+
const ignoredFilePath = writeProjectFile(rootPath, 'src/ignored.ts');
145146
writeProjectFile(rootPath, 'src/index.ts');
146-
const checkedDirectories: string[] = [];
147+
const checkedPaths: { path: string; isDirectory: boolean }[] = [];
147148
const generatedPath = path.join(rootPath, 'generated');
148-
const isDirectoryIgnored = (directoryPath: string): boolean => {
149-
checkedDirectories.push(path.relative(rootPath, directoryPath));
150-
return directoryPath === generatedPath;
149+
const isIgnored = (filePath: string, isDirectory: boolean): boolean => {
150+
checkedPaths.push({
151+
path: path.relative(rootPath, filePath),
152+
isDirectory,
153+
});
154+
return isDirectory ? filePath === generatedPath : filePath === ignoredFilePath;
151155
};
152156

153-
const files = await discoverFmtPaths({ cwd: rootPath, isDirectoryIgnored });
157+
const files = await discoverFmtPaths({ cwd: rootPath, isIgnored });
154158
const ignoredRoot = await discoverFmtPaths({
155159
cwd: rootPath,
156160
patterns: ['generated'],
157-
isDirectoryIgnored,
161+
isIgnored,
158162
});
159163

160164
expect(relativePaths(rootPath, files)).toEqual([path.join('src', 'index.ts')]);
161165
expect(ignoredRoot).toEqual([]);
162-
expect(checkedDirectories).toContain('generated');
163-
expect(checkedDirectories).not.toContain(path.join('generated', 'nested'));
166+
expect(checkedPaths).toContainEqual({ path: 'generated', isDirectory: true });
167+
expect(checkedPaths).toContainEqual({
168+
path: path.join('src', 'ignored.ts'),
169+
isDirectory: false,
170+
});
171+
expect(checkedPaths).not.toContainEqual({
172+
path: path.join('generated', 'nested'),
173+
isDirectory: true,
174+
});
164175
});
165176
});
166177

0 commit comments

Comments
 (0)