From 56b779b82809e099f61cec000b7f19edab2ee5c4 Mon Sep 17 00:00:00 2001 From: Tiago Danin Date: Mon, 17 Jun 2019 03:02:31 -0300 Subject: [PATCH] Add `findUp.exists()` and `findUp.sync.exists()` (#41) Co-authored-by: Sindre Sorhus --- index.d.ts | 96 ++++++++++++++++++++++++++++++++++++++++--------- index.js | 5 +++ index.test-d.ts | 3 ++ package.json | 3 +- readme.md | 32 +++++++++++------ test.js | 26 +++++++++++++- 6 files changed, 137 insertions(+), 28 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1e7d818..1ca9a20 100644 --- a/index.d.ts +++ b/index.d.ts @@ -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'); @@ -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), options?: findUp.Options): Promise; + 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; /** Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`. diff --git a/index.js b/index.js index ea81c3f..ce564e5 100644 --- a/index.js +++ b/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'); @@ -81,4 +82,8 @@ module.exports.sync = (name, options = {}) => { } }; +module.exports.exists = pathExists; + +module.exports.sync.exists = pathExists.sync; + module.exports.stop = stop; diff --git a/index.test-d.ts b/index.test-d.ts index 017ccfd..7293daa 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -71,4 +71,7 @@ expectType(findUp.sync((): findUp.StopSymbol => findUp.stop, expectType(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'file'})); expectType(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'directory'})); +expectType>(findUp.exists('unicorn.png')); +expectType(findUp.sync.exists('unicorn.png')); + expectType(findUp.stop); diff --git a/package.json b/package.json index bd9656a..d1d1b89 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/readme.md b/readme.md index 4af713d..4d8fff1 100644 --- a/readme.md +++ b/readme.md @@ -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'); @@ -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' })(); ``` @@ -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` 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. diff --git a/test.js b/test.js index 3843a93..73578da 100644 --- a/test.js +++ b/test.js @@ -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); @@ -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; @@ -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')); +});