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

Add ability to specify if looking for file or directory, only match files by default #40

Merged
merged 4 commits into from May 7, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions fixture/directory-link
1 change: 1 addition & 0 deletions fixture/file-link
20 changes: 18 additions & 2 deletions index.d.ts
Expand Up @@ -8,6 +8,22 @@ declare namespace findUp {
readonly cwd?: string;
}

interface FullOptions extends Options {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know TypeScript that well, could this be imported from locate-path (and if it can should it)?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can import it at line 1:

import {Options as LocatePathOptions} from 'locate-path';

And then extend it on line 2:

interface Options extends LocatePathOptions {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually Options is for using a matcher function where only cwd is accepted.

For the normal mode technically locatePath.AsyncOptions is supported, though I'm not sure we want TS to allow concurrency and preserveOrder to be used? For now my patch is using locatePath.AsyncOptions but can easily be switched to locatePath.Options.

Also instead of extending the locate-path options I just directly used them since this module does not add any new 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;
}

Expand Down Expand Up @@ -41,7 +57,7 @@ declare const findUp: {
})();
```
*/
(name: string | string[], options?: findUp.Options): Promise<string | undefined>;
(name: string | string[], options?: findUp.FullOptions): Promise<string | undefined>;

/**
Find a file or directory by walking up parent directories.
Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions index.js
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions index.test-d.ts
Expand Up @@ -5,6 +5,11 @@ expectType<Promise<string | undefined>>(findUp('unicorn.png'));
expectType<Promise<string | undefined>>(findUp('unicorn.png', {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png']));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {type: 'directory'}));

expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png'));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(() => undefined));
Expand All @@ -22,6 +27,11 @@ expectType<string | undefined>(findUp.sync('unicorn.png'));
expectType<string | undefined>(findUp.sync('unicorn.png', {cwd: ''}));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png']));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {cwd: ''}));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {allowSymlinks: true}));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {allowSymlinks: false}));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {type: 'file'}));
expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {type: 'directory'}));

expectType<string | undefined>(findUp.sync(() => 'unicorn.png'));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {cwd: ''}));
expectType<string | undefined>(findUp.sync(() => undefined));
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -40,7 +40,7 @@
"path"
],
"dependencies": {
"locate-path": "^4.0.0"
"locate-path": "^5.0.0"
},
"devDependencies": {
"ava": "^1.4.1",
Expand Down
15 changes: 15 additions & 0 deletions readme.md
Expand Up @@ -106,6 +106,21 @@ Default: `process.cwd()`

Directory to start from.

##### type
coreyfarrell marked this conversation as resolved.
Show resolved Hide resolved

Type: `string`<br>
Default: `file`<br>
Values: `file` `directory`

The type of paths that can match.

##### allowSymlinks

Type: `boolean`<br>
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.
Expand Down
78 changes: 61 additions & 17 deletions test.js
Expand Up @@ -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
Expand All @@ -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 => {
Expand All @@ -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
Expand Down Expand Up @@ -136,15 +170,17 @@ 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);
});

test('sync (cwd)', t => {
const foundPath = findUp.sync(name.packageDirectory, {
cwd: absolute.packageDirectory
cwd: absolute.packageDirectory,
type: 'directory'
});

t.is(foundPath, absolute.packageDirectory);
Expand Down Expand Up @@ -179,73 +215,79 @@ 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);
});

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);
});

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);
});

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);
});

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);
});

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);
});
Expand All @@ -264,15 +306,17 @@ 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);
});

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);
Expand Down