From 7c1bf216597e0fecd7f9102b67c9eee29abf4f93 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 4 May 2019 12:03:27 -0400 Subject: [PATCH 1/4] Add ability to specify if looking for file or directory By default directories will no longer match. Fixes #33 --- fixture/directory-link | 1 + fixture/file-link | 1 + index.d.ts | 20 +++++++++-- index.js | 4 +-- index.test-d.ts | 10 ++++++ package.json | 2 +- readme.md | 15 ++++++++ test.js | 78 +++++++++++++++++++++++++++++++++--------- 8 files changed, 109 insertions(+), 22 deletions(-) create mode 120000 fixture/directory-link create mode 120000 fixture/file-link diff --git a/fixture/directory-link b/fixture/directory-link new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/fixture/directory-link @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/fixture/file-link b/fixture/file-link new file mode 120000 index 0000000..250a17a --- /dev/null +++ b/fixture/file-link @@ -0,0 +1 @@ +baz.js \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 425e324..5c72f3a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -8,6 +8,22 @@ declare namespace findUp { readonly cwd?: string; } + interface FullOptions extends Options { + /** + Type of path to find. + + @default 'file' + */ + readonly type?: 'file' | 'directory'; + + /** + Allow symbolic links to match if they point to the requested path type. + + @default true + */ + readonly allowSymlinks?: boolean; + } + type Match = string | symbol | undefined; } @@ -41,7 +57,7 @@ declare const findUp: { })(); ``` */ - (name: string | string[], options?: findUp.Options): Promise; + (name: string | string[], options?: findUp.FullOptions): Promise; /** Find a file or directory by walking up parent directories. @@ -57,7 +73,7 @@ declare const findUp: { @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; + sync(name: string | string[], options?: findUp.FullOptions): string | undefined; /** Synchronously find a file or directory by walking up parent directories. diff --git a/index.js b/index.js index 35c261d..0bd0b19 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,7 @@ module.exports = async (name, options = {}) => { // eslint-disable-next-line no-constant-condition while (true) { // eslint-disable-next-line no-await-in-loop - const foundPath = await (typeof name === 'function' ? name(directory) : locatePath(paths, {cwd: directory})); + const foundPath = await (typeof name === 'function' ? name(directory) : locatePath(paths, {...options, cwd: directory})); if (foundPath === stop) { return; @@ -36,7 +36,7 @@ module.exports.sync = (name, options = {}) => { // eslint-disable-next-line no-constant-condition while (true) { - const foundPath = typeof name === 'function' ? name(directory) : locatePath.sync(paths, {cwd: directory}); + const foundPath = typeof name === 'function' ? name(directory) : locatePath.sync(paths, {...options, cwd: directory}); if (foundPath === stop) { return; diff --git a/index.test-d.ts b/index.test-d.ts index 42b1397..bea7a80 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -5,6 +5,11 @@ expectType>(findUp('unicorn.png')); expectType>(findUp('unicorn.png', {cwd: ''})); expectType>(findUp(['rainbow.png', 'unicorn.png'])); expectType>(findUp(['rainbow.png', 'unicorn.png'], {cwd: ''})); +expectType>(findUp(['rainbow.png', 'unicorn.png'], {allowSymlinks: true})); +expectType>(findUp(['rainbow.png', 'unicorn.png'], {allowSymlinks: false})); +expectType>(findUp(['rainbow.png', 'unicorn.png'], {type: 'file'})); +expectType>(findUp(['rainbow.png', 'unicorn.png'], {type: 'directory'})); + expectType>(findUp(() => 'unicorn.png')); expectType>(findUp(() => 'unicorn.png', {cwd: ''})); expectType>(findUp(() => undefined)); @@ -22,6 +27,11 @@ expectType(findUp.sync('unicorn.png')); expectType(findUp.sync('unicorn.png', {cwd: ''})); expectType(findUp.sync(['rainbow.png', 'unicorn.png'])); expectType(findUp.sync(['rainbow.png', 'unicorn.png'], {cwd: ''})); +expectType(findUp.sync(['rainbow.png', 'unicorn.png'], {allowSymlinks: true})); +expectType(findUp.sync(['rainbow.png', 'unicorn.png'], {allowSymlinks: false})); +expectType(findUp.sync(['rainbow.png', 'unicorn.png'], {type: 'file'})); +expectType(findUp.sync(['rainbow.png', 'unicorn.png'], {type: 'directory'})); + expectType(findUp.sync(() => 'unicorn.png')); expectType(findUp.sync(() => 'unicorn.png', {cwd: ''})); expectType(findUp.sync(() => undefined)); diff --git a/package.json b/package.json index cb92c5a..9b35999 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "path" ], "dependencies": { - "locate-path": "^4.0.0" + "locate-path": "^5.0.0" }, "devDependencies": { "ava": "^1.4.1", diff --git a/readme.md b/readme.md index c0fbbf5..a9224c9 100644 --- a/readme.md +++ b/readme.md @@ -106,6 +106,21 @@ Default: `process.cwd()` Directory to start from. +##### type + +Type: `string`
+Default: `file`
+Values: `file` `directory` + +The type of paths that can match. + +##### allowSymlinks + +Type: `boolean`
+Default: `true` + +Allow symbolic links to match if they point to the chosen path type. + ### 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 8fbb5d6..d9c68ea 100644 --- a/test.js +++ b/test.js @@ -12,7 +12,9 @@ const name = { fixtureDirectory: 'fixture', modulesDirectory: 'node_modules', baz: 'baz.js', - qux: 'qux.js' + qux: 'qux.js', + fileLink: 'file-link', + directoryLink: 'directory-link' }; // These paths are relative to the project root @@ -35,6 +37,8 @@ absolute.fixtureDirectory = path.join( absolute.baz = path.join(absolute.fixtureDirectory, name.baz); absolute.qux = path.join(absolute.fixtureDirectory, name.qux); absolute.barDir = path.join(absolute.fixtureDirectory, 'foo', 'bar'); +absolute.fileLink = path.join(absolute.fixtureDirectory, name.fileLink); +absolute.directoryLink = path.join(absolute.fixtureDirectory, name.directoryLink); // Create a disjoint directory, used for the not-found tests test.beforeEach(t => { @@ -59,17 +63,47 @@ test('sync (child file)', t => { }); test('async (child directory)', async t => { - const foundPath = await findUp(name.fixtureDirectory); + const foundPath = await findUp(name.fixtureDirectory, {type: 'directory'}); t.is(foundPath, absolute.fixtureDirectory); }); test('sync (child directory)', t => { - const foundPath = findUp.sync(name.fixtureDirectory); + const foundPath = findUp.sync(name.fixtureDirectory, {type: 'directory'}); t.is(foundPath, absolute.fixtureDirectory); }); +test('async (explicit type file)', async t => { + t.is(await findUp(name.packageJson, {type: 'file'}), absolute.packageJson); + t.is(await findUp(name.packageJson, {type: 'directory'}), undefined); +}); + +test('sync (explicit type file)', t => { + t.is(findUp.sync(name.packageJson, {type: 'file'}), absolute.packageJson); + t.is(findUp.sync(name.packageJson, {type: 'directory'}), undefined); +}); + +test('async (symbolic links)', async t => { + const cwd = absolute.fixtureDirectory; + + t.is(await findUp(name.fileLink, {cwd}), absolute.fileLink); + t.is(await findUp(name.fileLink, {cwd, allowSymlinks: false}), undefined); + + t.is(await findUp(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); + t.is(await findUp(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); +}); + +test('sync (symbolic links)', t => { + const cwd = absolute.fixtureDirectory; + + t.is(findUp.sync(name.fileLink, {cwd}), absolute.fileLink); + t.is(findUp.sync(name.fileLink, {cwd, allowSymlinks: false}), undefined); + + t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); + t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); +}); + test('async (child file, custom cwd)', async t => { const foundPath = await findUp(name.baz, { cwd: relative.fixtureDirectory @@ -136,7 +170,8 @@ test('sync (second child file, array, custom cwd)', t => { test('async (cwd)', async t => { const foundPath = await findUp(name.packageDirectory, { - cwd: absolute.packageDirectory + cwd: absolute.packageDirectory, + type: 'directory' }); t.is(foundPath, absolute.packageDirectory); @@ -144,7 +179,8 @@ test('async (cwd)', async t => { test('sync (cwd)', t => { const foundPath = findUp.sync(name.packageDirectory, { - cwd: absolute.packageDirectory + cwd: absolute.packageDirectory, + type: 'directory' }); t.is(foundPath, absolute.packageDirectory); @@ -179,20 +215,21 @@ test('sync (nested descendant file)', t => { }); test('async (nested descendant directory)', async t => { - const foundPath = await findUp(relative.barDir); + const foundPath = await findUp(relative.barDir, {type: 'directory'}); t.is(foundPath, absolute.barDir); }); test('sync (nested descendant directory)', t => { - const foundPath = findUp.sync(relative.barDir); + const foundPath = findUp.sync(relative.barDir, {type: 'directory'}); t.is(foundPath, absolute.barDir); }); test('async (nested descendant directory, custom cwd)', async t => { const filePath = await findUp(relative.barDir, { - cwd: relative.modulesDirectory + cwd: relative.modulesDirectory, + type: 'directory' }); t.is(filePath, absolute.barDir); @@ -200,7 +237,8 @@ test('async (nested descendant directory, custom cwd)', async t => { test('sync (nested descendant directory, custom cwd)', t => { const filePath = findUp.sync(relative.barDir, { - cwd: relative.modulesDirectory + cwd: relative.modulesDirectory, + type: 'directory' }); t.is(filePath, absolute.barDir); @@ -208,7 +246,8 @@ test('sync (nested descendant directory, custom cwd)', t => { test('async (nested cousin directory, custom cwd)', async t => { const foundPath = await findUp(relative.barDir, { - cwd: relative.fixtureDirectory + cwd: relative.fixtureDirectory, + type: 'directory' }); t.is(foundPath, absolute.barDir); @@ -216,7 +255,8 @@ test('async (nested cousin directory, custom cwd)', async t => { test('sync (nested cousin directory, custom cwd)', t => { const foundPath = findUp.sync(relative.barDir, { - cwd: relative.fixtureDirectory + cwd: relative.fixtureDirectory, + type: 'directory' }); t.is(foundPath, absolute.barDir); @@ -224,7 +264,8 @@ test('sync (nested cousin directory, custom cwd)', t => { test('async (ancestor directory, custom cwd)', async t => { const foundPath = await findUp(name.fixtureDirectory, { - cwd: relative.barDir + cwd: relative.barDir, + type: 'directory' }); t.is(foundPath, absolute.fixtureDirectory); @@ -232,20 +273,21 @@ test('async (ancestor directory, custom cwd)', async t => { test('sync (ancestor directory, custom cwd)', t => { const foundPath = findUp.sync(name.fixtureDirectory, { - cwd: relative.barDir + cwd: relative.barDir, + type: 'directory' }); t.is(foundPath, absolute.fixtureDirectory); }); test('async (absolute directory)', async t => { - const filePath = await findUp(absolute.barDir); + const filePath = await findUp(absolute.barDir, {type: 'directory'}); t.is(filePath, absolute.barDir); }); test('sync (absolute directory)', t => { - const filePath = findUp.sync(absolute.barDir); + const filePath = findUp.sync(absolute.barDir, {type: 'directory'}); t.is(filePath, absolute.barDir); }); @@ -264,7 +306,8 @@ test('sync (not found, absolute file)', t => { test('async (absolute directory, disjoint cwd)', async t => { const filePath = await findUp(absolute.barDir, { - cwd: t.context.disjoint + cwd: t.context.disjoint, + type: 'directory' }); t.is(filePath, absolute.barDir); @@ -272,7 +315,8 @@ test('async (absolute directory, disjoint cwd)', async t => { test('sync (absolute directory, disjoint cwd)', t => { const filePath = findUp.sync(absolute.barDir, { - cwd: t.context.disjoint + cwd: t.context.disjoint, + type: 'directory' }); t.is(filePath, absolute.barDir); From a9ba4e9008a81295edd791ce2618bff20d01c166 Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sat, 4 May 2019 12:24:21 -0400 Subject: [PATCH 2/4] Skip symlink tests on Windows --- test.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test.js b/test.js index d9c68ea..a1a9564 100644 --- a/test.js +++ b/test.js @@ -84,25 +84,27 @@ test('sync (explicit type file)', t => { t.is(findUp.sync(name.packageJson, {type: 'directory'}), undefined); }); -test('async (symbolic links)', async t => { - const cwd = absolute.fixtureDirectory; +if (process.platform !== 'win32') { + test('async (symbolic links)', async t => { + const cwd = absolute.fixtureDirectory; - t.is(await findUp(name.fileLink, {cwd}), absolute.fileLink); - t.is(await findUp(name.fileLink, {cwd, allowSymlinks: false}), undefined); + t.is(await findUp(name.fileLink, {cwd}), absolute.fileLink); + t.is(await findUp(name.fileLink, {cwd, allowSymlinks: false}), undefined); - t.is(await findUp(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); - t.is(await findUp(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); -}); + t.is(await findUp(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); + t.is(await findUp(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); + }); -test('sync (symbolic links)', t => { - const cwd = absolute.fixtureDirectory; + test('sync (symbolic links)', t => { + const cwd = absolute.fixtureDirectory; - t.is(findUp.sync(name.fileLink, {cwd}), absolute.fileLink); - t.is(findUp.sync(name.fileLink, {cwd, allowSymlinks: false}), undefined); + t.is(findUp.sync(name.fileLink, {cwd}), absolute.fileLink); + t.is(findUp.sync(name.fileLink, {cwd, allowSymlinks: false}), undefined); - t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); - t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); -}); + t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory'}), absolute.directoryLink); + t.is(findUp.sync(name.directoryLink, {cwd, type: 'directory', allowSymlinks: false}), undefined); + }); +} test('async (child file, custom cwd)', async t => { const foundPath = await findUp(name.baz, { From b5e7d5a376e009f55e93d6c208486af99b43ab6a Mon Sep 17 00:00:00 2001 From: Corey Farrell Date: Sun, 5 May 2019 18:15:23 -0400 Subject: [PATCH 3/4] Link TS options to locate-path, document options accepted with matcher. --- index.d.ts | 22 ++++------------------ readme.md | 2 +- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5c72f3a..9d8f281 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,3 +1,5 @@ +import * as locatePath from 'locate-path'; + declare namespace findUp { interface Options { /** @@ -8,22 +10,6 @@ declare namespace findUp { readonly cwd?: string; } - interface FullOptions extends Options { - /** - Type of path to find. - - @default 'file' - */ - readonly type?: 'file' | 'directory'; - - /** - Allow symbolic links to match if they point to the requested path type. - - @default true - */ - readonly allowSymlinks?: boolean; - } - type Match = string | symbol | undefined; } @@ -57,7 +43,7 @@ declare const findUp: { })(); ``` */ - (name: string | string[], options?: findUp.FullOptions): Promise; + (name: string | string[], options?: locatePath.AsyncOptions): Promise; /** Find a file or directory by walking up parent directories. @@ -73,7 +59,7 @@ declare const findUp: { @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.FullOptions): string | undefined; + sync(name: string | string[], options?: locatePath.Options): string | undefined; /** Synchronously find a file or directory by walking up parent directories. diff --git a/readme.md b/readme.md index a9224c9..0268486 100644 --- a/readme.md +++ b/readme.md @@ -93,7 +93,7 @@ Type: `Function` A function that will be called with each directory until it returns a `string` with the path, which stops the search, or the root directory has been reached and nothing was found. Useful if you want to match files with certain patterns, set of permissions, or other advanced use cases. -When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path. +When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path. When a `matcher` function is used only the `cwd` option is supported. #### options From b5880f77265e93213a327c7e990fd2aa0490b772 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 7 May 2019 11:06:19 +0700 Subject: [PATCH 4/4] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0268486..bcb845f 100644 --- a/readme.md +++ b/readme.md @@ -93,7 +93,7 @@ Type: `Function` A function that will be called with each directory until it returns a `string` with the path, which stops the search, or the root directory has been reached and nothing was found. Useful if you want to match files with certain patterns, set of permissions, or other advanced use cases. -When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path. When a `matcher` function is used only the `cwd` option is supported. +When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path. When a `matcher` function is used, only the `cwd` option is supported. #### options