Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:privatenumber/fs.promises.exists
Browse files Browse the repository at this point in the history
  • Loading branch information
privatenumber committed Nov 10, 2021
2 parents b475dde + abe8268 commit 3ed0c72
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 43 deletions.
65 changes: 50 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
// Necessary CJS style for rollup to convert to ESM
import fs = require('fs');
import path = require('path');

const isPathPattern = /^[./]/;

const inArray = (
array: string[],
subject: string,
caseSensitive: boolean,
) => {
if (caseSensitive) {
return array.includes(subject) ? subject : false;
}

const subjectLowerCase = subject.toLowerCase();
return array.find(element => element.toLowerCase() === subjectLowerCase);
};

const readdir = (directoryPath: string) => fs.promises.readdir(directoryPath).catch(() => null);

/**
Returns a promise that resolves to a boolean indicating whether the file exists.
Expand Down Expand Up @@ -28,25 +44,44 @@ async function fsExists(
filePath: string,
caseSensitive?: boolean,
) {
if (caseSensitive !== undefined) {
const directoryPath = path.dirname(filePath);
const directoryFiles = await fs.promises.readdir(directoryPath);
const fileName = path.basename(filePath);
if (caseSensitive === undefined) {
return await fs.promises.access(filePath).then(
() => true,
() => false,
);
}

if (caseSensitive) {
return directoryFiles.includes(fileName);
}
const filePathSteps = filePath.split('/');
const validSteps: string[] = [];

const fileNameLowerCase = fileName.toLowerCase();
const found = directoryFiles.find(name => name.toLowerCase() === fileNameLowerCase);
let parentDirectory: string[] | null = null;

return found ? path.join(directoryPath, found) : false;
if (!isPathPattern.test(filePath)) {
parentDirectory = await readdir('.');
}

return await fs.promises.access(filePath).then(
() => true,
() => false,
);
for (let i = 0; i < filePathSteps.length; i += 1) {
let step = filePathSteps[i];

if (parentDirectory) {
const foundInParentDirectory = inArray(parentDirectory, step, caseSensitive);
if (!foundInParentDirectory) {
return false;
}

step = foundInParentDirectory;
}

const checkPath = [...validSteps, step].join('/') || '/';

// Last step
if (i === filePathSteps.length - 1) {
return caseSensitive ? true : checkPath;
}

parentDirectory = await readdir(checkPath);
validSteps.push(step);
}
}

export = fsExists;
1 change: 1 addition & 0 deletions test/fixture/CASE-SENSITIVE/case-insensitive/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello
116 changes: 88 additions & 28 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,100 @@
import { test } from 'uvu';
import path from 'path';
import { suite, Test } from 'uvu';
import * as assert from 'uvu/assert'; // eslint-disable-line node/file-extension-in-import
import fsExists from '../src/index';

test('exists', async () => {
const exists = await fsExists('./package.json');
assert.is(exists, true);
});
// https://github.com/lukeed/uvu/issues/43
function describe(name: string, function_: (test: Test) => void) {
const s = suite(name);
function_(s);
s.run();
}

test('doesn\'t exist', async () => {
const exists = await fsExists('./random-non-existent-file');
assert.is(exists, false);
});
const fixturePath = 'test/fixture/CASE-SENSITIVE/case-insensitive/file.txt';
const existentPath = {
relativeShort: fixturePath,
relative: `./${fixturePath}`,
absolute: path.resolve(fixturePath),
caseInsensitive: fixturePath.toUpperCase(),
};

test('case-sensitive: doesn\'t exist', async () => {
const exists = await fsExists('PACKAGE.json', true);
assert.is(exists, false);
});
const nonExistenent = {
file: 'random-non-existent-file',
directory: 'random-non-existent-dir/random-non-existent-file',
};

test('case-sensitive: exists', async () => {
const exists = await fsExists('package.json', true);
assert.is(exists, true);
});
describe('basic', (test) => {
test('exists', async () => {
const exists = await fsExists(existentPath.relativeShort);
assert.is(exists, true);
});

test('case-insensitive: exist 1', async () => {
const exists = await fsExists('PACKAGE.json', false);
assert.is(exists, 'package.json');
test('doesnt exist', async () => {
const exists = await fsExists(nonExistenent.file);
assert.is(exists, false);
});
});

test('case-insensitive: exists 2', async () => {
const exists = await fsExists('package.json', false);
assert.is(exists, 'package.json');
});
describe('case sensitive', (test) => {
test('exists - relative path', async () => {
const exists = await fsExists(existentPath.relative, true);
assert.is(exists, true);
});

test('exists - relative path with no ./', async () => {
const exists = await fsExists(existentPath.relativeShort, true);
assert.is(exists, true);
});

test('exists - absolute path', async () => {
const exists = await fsExists(existentPath.absolute, true);
assert.is(exists, true);
});

test('exists - case insensitive', async () => {
const exists = await fsExists(existentPath.caseInsensitive, true);
assert.is(exists, false);
});

test('case-insensitive: doesn\'t exists', async () => {
const exists = await fsExists('random-non-existent-file.json', false);
assert.is(exists, false);
test('file doesnt exist', async () => {
const exists = await fsExists(nonExistenent.file, true);
assert.is(exists, false);
});

test('directory doesnt exist', async () => {
const exists = await fsExists(nonExistenent.directory, true);
assert.is(exists, false);
});
});

test.run();
describe('case insensitive', (test) => {
test('exists - relative path', async () => {
const exists = await fsExists(existentPath.relative, false);
assert.is(exists, existentPath.relative);
});

test('exists - relative path with no ./', async () => {
const exists = await fsExists(existentPath.relativeShort, false);
assert.is(exists, existentPath.relativeShort);
});

test('exists - absolute path', async () => {
const exists = await fsExists(existentPath.absolute, false);
assert.is(exists, existentPath.absolute);
});

test('exists - case insensitive', async () => {
const exists = await fsExists(existentPath.caseInsensitive, false);
assert.is(exists, existentPath.relativeShort);
});

test('file doesnt exist', async () => {
const exists = await fsExists('file.txt', false);
assert.is(exists, false);
});

test('directory doesnt exist', async () => {
const exists = await fsExists('some-dir/file.txt', false);
assert.is(exists, false);
});
});

0 comments on commit 3ed0c72

Please sign in to comment.