Skip to content

Commit

Permalink
Add findUp.exists() and findUp.sync.exists() (#41)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
TiagoDanin and sindresorhus committed Jun 17, 2019
1 parent 4da9654 commit 56b779b
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 28 deletions.
96 changes: 80 additions & 16 deletions index.d.ts
Expand Up @@ -21,12 +21,12 @@ declare const findUp: {
```
// /
// └── Users
// └── sindresorhus
// ├── unicorn.png
// └── foo
// └── bar
// ├── baz
// └── example.js
// └── sindresorhus
// ├── unicorn.png
// └── foo
// └── bar
// ├── baz
// └── example.js
// example.js
import findUp = require('find-up');
Expand All @@ -47,24 +47,88 @@ declare const findUp: {
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
@returns The first path found or `undefined` if none could be found.
@example
```
import path = require('path');
import findUp = require('find-up');
(async () => {
console.log(await findUp(async directory => {
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();
```
*/
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;

sync: {
/**
Synchronously find a file or directory by walking up parent directories.
@param name - Name of the file or directory to find. Can be multiple.
@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
*/
(name: string | string[], options?: findUp.Options): string | undefined;

/**
Synchronously find a file or directory by walking up parent directories.
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
@returns The first path found or `undefined` if none could be found.
@example
```
import path = require('path');
import findUp = require('find-up');
console.log(findUp.sync(directory => {
const hasUnicorns = findUp.sync.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
```
*/
(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;

/**
Synchronously check if a path exists.
@param path - Path to the file or directory.
@returns Whether the path exists.
@example
```
import path = require('path');
import findUp = require('find-up');
console.log(findUp.sync.exists(path.join('/Users', 'sindresorhus', 'unicorn.png')));
//=> true
```
*/
exists(path: string): boolean;
}

/**
Synchronously find a file or directory by walking up parent directories.
Check if a path exists.
@param name - Name of the file or directory to find. Can be multiple.
@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
*/
sync(name: string | string[], options?: findUp.Options): string | undefined;
@param path - Path to a file or directory.
@returns Whether the path exists.
/**
Synchronously find a file or directory by walking up parent directories.
@example
```
import path = require('path');
import findUp = require('find-up');
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
@returns The first path found or `undefined` if none could be found.
(async () => {
console.log(await findUp.exists(path.join('/Users', 'sindresorhus', 'unicorn.png')));
//=> true
})();
```
*/
sync(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;
exists(path: string): Promise<boolean>;

/**
Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
Expand Down
5 changes: 5 additions & 0 deletions index.js
@@ -1,6 +1,7 @@
'use strict';
const path = require('path');
const locatePath = require('locate-path');
const pathExists = require('path-exists');

const stop = Symbol('findUp.stop');

Expand Down Expand Up @@ -81,4 +82,8 @@ module.exports.sync = (name, options = {}) => {
}
};

module.exports.exists = pathExists;

module.exports.sync.exists = pathExists.sync;

module.exports.stop = stop;
3 changes: 3 additions & 0 deletions index.test-d.ts
Expand Up @@ -71,4 +71,7 @@ expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop,
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'file'}));
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'directory'}));

expectType<Promise<boolean>>(findUp.exists('unicorn.png'));
expectType<boolean>(findUp.sync.exists('unicorn.png'));

expectType<Symbol>(findUp.stop);
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -40,7 +40,8 @@
"path"
],
"dependencies": {
"locate-path": "^5.0.0"
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"devDependencies": {
"ava": "^1.4.1",
Expand Down
32 changes: 22 additions & 10 deletions readme.md
Expand Up @@ -15,18 +15,17 @@ $ npm install find-up
```
/
└── Users
└── sindresorhus
├── unicorn.png
└── foo
└── bar
├── baz
└── example.js
└── sindresorhus
├── unicorn.png
└── foo
└── bar
├── baz
└── example.js
```

`example.js`

```js
const fs = require('fs');
const path = require('path');
const findUp = require('find-up');

Expand All @@ -37,11 +36,10 @@ const findUp = require('find-up');
console.log(await findUp(['rainbow.png', 'unicorn.png']));
//=> '/Users/sindresorhus/unicorn.png'

const pathExists = filePath => fs.promises.access(filePath).then(_ => true).catch(_ => false);
console.log(await findUp(async directory => {
const hasUnicorns = await pathExists(path.join(directory, 'unicorn.png'));
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}}, {type: 'directory'});
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();
```
Expand Down Expand Up @@ -107,6 +105,20 @@ Default: `true`

Allow symbolic links to match if they point to the chosen path type.

### findUp.exists(path)

Returns a `Promise<boolean>` of whether the path exists.

### findUp.sync.exists(path)

Returns a `boolean` of whether the path exists.

#### path

Type: `string`

Path to a file or directory.

### findUp.stop

A [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) that can be returned by a `matcher` function to stop the search and cause `findUp` to immediately return `undefined`. Useful as a performance optimization in case the current working directory is deeply nested in the filesystem.
Expand Down
26 changes: 25 additions & 1 deletion test.js
Expand Up @@ -50,6 +50,8 @@ test.afterEach(t => {
fs.rmdirSync(t.context.disjoint);
});

const isWindows = process.platform === 'win32';

test('async (child file)', async t => {
const foundPath = await findUp(name.packageJson);

Expand Down Expand Up @@ -84,7 +86,7 @@ test('sync (explicit type file)', t => {
t.is(findUp.sync(name.packageJson, {type: 'directory'}), undefined);
});

if (process.platform !== 'win32') {
if (!isWindows) {
test('async (symbolic links)', async t => {
const cwd = absolute.fixtureDirectory;

Expand Down Expand Up @@ -506,3 +508,25 @@ test('sync (matcher function stops early)', t => {
t.true(visited.has(cwd));
t.is(visited.size, 1);
});

test('async (check if path exists)', async t => {
if (!isWindows) {
t.true(await findUp.exists(absolute.directoryLink));
t.true(await findUp.exists(absolute.fileLink));
}

t.true(await findUp.exists(absolute.barDir));
t.true(await findUp.exists(absolute.packageJson));
t.false(await findUp.exists('fake'));
});

test('sync (check if path exists)', t => {
if (!isWindows) {
t.true(findUp.sync.exists(absolute.directoryLink));
t.true(findUp.sync.exists(absolute.fileLink));
}

t.true(findUp.sync.exists(absolute.barDir));
t.true(findUp.sync.exists(absolute.packageJson));
t.false(findUp.sync.exists('fake'));
});

0 comments on commit 56b779b

Please sign in to comment.