fix: prevent EISDIR crash when customIgnoreFilePaths contains directories (#19868) (#19898)

Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
Suhaan Raqeeb Khavas
2026-05-12 02:16:08 +05:30
committed by GitHub
parent c0d5ab1f1e
commit 8e58df72c6
4 changed files with 53 additions and 3 deletions
@@ -502,6 +502,50 @@ describe('FileDiscoveryService', () => {
const paths = service.getAllIgnoreFilePaths();
expect(paths[0]).toBe(path.join(projectRoot, '.gitignore'));
});
it('should exclude directories from getIgnoreFilePaths (#19868)', async () => {
// Create a directory that shares a name with a customIgnoreFilePaths entry
await fs.mkdir(path.join(projectRoot, 'node_modules'), {
recursive: true,
});
const service = new FileDiscoveryService(projectRoot, {
customIgnoreFilePaths: ['node_modules'],
});
const paths = service.getIgnoreFilePaths();
// node_modules/ is a directory, not a file — it should be excluded
expect(paths).not.toContain(path.join(projectRoot, 'node_modules'));
});
it('should exclude directories from getAllIgnoreFilePaths (#19868)', async () => {
await fs.mkdir(path.join(projectRoot, 'node_modules'), {
recursive: true,
});
const service = new FileDiscoveryService(projectRoot, {
customIgnoreFilePaths: ['node_modules'],
});
const paths = service.getAllIgnoreFilePaths();
expect(paths).not.toContain(path.join(projectRoot, 'node_modules'));
// .gitignore should still be present
expect(paths).toContain(path.join(projectRoot, '.gitignore'));
});
it('should not crash when customIgnoreFilePaths contains directory names (#19868)', async () => {
await fs.mkdir(path.join(projectRoot, 'node_modules'), {
recursive: true,
});
await fs.mkdir(path.join(projectRoot, 'temp'), { recursive: true });
// This is the exact user scenario from issue #19868
expect(() => {
new FileDiscoveryService(projectRoot, {
customIgnoreFilePaths: ['node_modules/', 'temp/', 'cache/'],
});
}).not.toThrow();
});
});
describe('getIgnoredPaths', () => {
@@ -274,7 +274,8 @@ export class FileDiscoveryService {
this.defaultFilterFileOptions.respectGitIgnore
) {
const gitIgnorePath = path.join(this.projectRoot, '.gitignore');
if (fs.existsSync(gitIgnorePath)) {
const stat = fs.statSync(gitIgnorePath, { throwIfNoEntry: false });
if (stat?.isFile()) {
paths.push(gitIgnorePath);
}
}
+3 -1
View File
@@ -19,8 +19,10 @@ export function loadIgnoreRules(
const ignoreFiles = service.getAllIgnoreFilePaths();
for (const filePath of ignoreFiles) {
if (fs.existsSync(filePath)) {
try {
ignorer.add(fs.readFileSync(filePath, 'utf8'));
} catch {
// Skip files that can't be read (e.g. directories, permission errors)
}
}
+4 -1
View File
@@ -105,7 +105,10 @@ export class IgnoreFileParser implements IgnoreFileFilter {
.slice()
.reverse()
.map((fileName) => path.join(this.projectRoot, fileName))
.filter((filePath) => fs.existsSync(filePath));
.filter(
(filePath) =>
fs.statSync(filePath, { throwIfNoEntry: false })?.isFile() ?? false,
);
}
/**