Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(find-all): prevent errors for inaccessible or deleted directories #52

Merged
merged 1 commit into from Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 14 additions & 6 deletions src/find-all.ts
Expand Up @@ -22,13 +22,21 @@ async function* findTSConfig(
visited: Set<string> = new Set<string>()
): AsyncGenerator<string> {
if (!visited.has(dir)) {
const dirents = await fs.readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
if (dirent.isDirectory() && (!options?.skip || !options.skip(dirent.name))) {
yield* findTSConfig(path.resolve(dir, dirent.name), options, visited);
} else if (dirent.isFile() && dirent.name === 'tsconfig.json') {
yield path.resolve(dir, dirent.name);
visited.add(dir);
try {
const dirents = await fs.readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
if (dirent.isDirectory() && (!options?.skip || !options.skip(dirent.name))) {
yield* findTSConfig(path.resolve(dir, dirent.name), options, visited);
} else if (dirent.isFile() && dirent.name === 'tsconfig.json') {
yield path.resolve(dir, dirent.name);
}
}
} catch (e) {
if (e.code === 'EACCES' || e.code === 'ENOENT') {
return; // directory inaccessible or deleted
}
throw e;
}
}
}
Expand Down
34 changes: 30 additions & 4 deletions tests/find-all.ts
Expand Up @@ -2,6 +2,7 @@ import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import path from 'path';
import { findAll } from '../src/find-all.js';
import * as fs from 'fs';
import glob from 'tiny-glob';
const test = suite('findAll');

Expand Down Expand Up @@ -52,13 +53,14 @@ test('should find tsconfig in child directory', async () => {
});

test('should find multiple tsconfig in child directories', async () => {
const expected = (await glob('tests/fixtures/**/tsconfig.json')).map((file) =>
const expected = (await glob('tests/fixtures/find-all/multiple/**/tsconfig.json')).map((file) =>
path.resolve(file)
);
expected.sort();
const found = await findAll(path.join('tests', 'fixtures'));

const found = await findAll(path.join('tests', 'fixtures', 'find-all', 'multiple'));
found.sort();
assert.equal(found, expected, 'found all tsconfig in test/fixtures');
assert.equal(found, expected, 'found all tsconfig in test/fixtures/find-all/multiple');
});

test('should handle directories with recursive symlinks', async () => {
Expand All @@ -71,7 +73,6 @@ test('should handle directories with recursive symlinks', async () => {
found.sort();
assert.equal(found, expected, 'found all tsconfig in test/fixtures/find-all/recursive-symlink');
});
test.run();

test('should exclude skipped directories', async () => {
const expected = [
Expand All @@ -88,4 +89,29 @@ test('should exclude skipped directories', async () => {
'found filtered tsconfig in test/fixtures/find-all/recursive-symlink'
);
});

test('should handle directories with inaccessible children', async () => {
const inaccessible = path.resolve(
'tests',
'fixtures',
'find-all',
'inaccessible-dir',
'_inaccessible'
);
try {
if (fs.existsSync(inaccessible)) {
fs.chmodSync(inaccessible, 0o000);
}
} catch (e) {
assert.unreachable(`failed to set inaccessible-child permissions: ${e}`);
}
const expected = [
path.resolve('tests', 'fixtures', 'find-all', 'inaccessible-dir', 'tsconfig.json')
];
expected.sort();
const found = await findAll(path.join('tests', 'fixtures', 'find-all', 'inaccessible-dir'));
found.sort();
assert.equal(found, expected, 'found all tsconfig in test/fixtures/find-all/inaccessible-dir');
});

test.run();
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.