Skip to content

Commit

Permalink
Enable type/allowSymlink matching for return value of matcher function (
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyfarrell authored and sindresorhus committed May 12, 2019
1 parent da1b331 commit 43cbbf9
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 35 deletions.
13 changes: 2 additions & 11 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ declare const stop: unique symbol;
declare namespace findUp {
interface Options extends LocatePathOptions {}

interface MatcherOptions {
/**
Directory to start from.
@default process.cwd()
*/
readonly cwd?: string;
}

type StopSymbol = typeof stop;

type Match = string | StopSymbol | undefined;
Expand Down Expand Up @@ -57,7 +48,7 @@ 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.
*/
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.MatcherOptions): Promise<string | undefined>;
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;

/**
Synchronously find a file or directory by walking up parent directories.
Expand All @@ -73,7 +64,7 @@ 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.
*/
sync(matcher: (directory: string) => findUp.Match, options?: findUp.MatcherOptions): string | undefined;
sync(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;

/**
Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
Expand Down
34 changes: 28 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,23 @@ module.exports = async (name, options = {}) => {
const {root} = path.parse(directory);
const paths = [].concat(name);

const runMatcher = async locateOptions => {
if (typeof name !== 'function') {
return locatePath(paths, locateOptions);
}

const foundPath = await name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath([foundPath], locateOptions);
}

return foundPath;
};

// 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, {...options, cwd: directory}));
const foundPath = await runMatcher({...options, cwd: directory});

if (foundPath === stop) {
return;
Expand All @@ -37,11 +48,22 @@ module.exports.sync = (name, options = {}) => {
const {root} = path.parse(directory);
const paths = [].concat(name);

const runMatcher = locateOptions => {
if (typeof name !== 'function') {
return locatePath.sync(paths, locateOptions);
}

const foundPath = name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath.sync([foundPath], locateOptions);
}

return foundPath;
};

// eslint-disable-next-line no-constant-condition
while (true) {
const foundPath = typeof name === 'function' ?
name(directory) :
locatePath.sync(paths, {...options, cwd: directory});
const foundPath = runMatcher({...options, cwd: directory});

if (foundPath === stop) {
return;
Expand Down
31 changes: 31 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,37 @@ expectError(findUp(['rainbow.png', 'unicorn.png'], {concurrency: 1}))

expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png'));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {type: 'directory'}));
expectType<Promise<string | undefined>>(findUp(() => undefined));
expectType<Promise<string | undefined>>(findUp(() => undefined, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(() => undefined, {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(() => undefined, {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(() => undefined, {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(() => undefined, {type: 'directory'}));
expectType<Promise<string | undefined>>(findUp((): findUp.StopSymbol => findUp.stop));
expectType<Promise<string | undefined>>(findUp((): findUp.StopSymbol => findUp.stop, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png'));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {type: 'directory'}));
expectType<Promise<string | undefined>>(findUp(async () => undefined));
expectType<Promise<string | undefined>>(findUp(async () => undefined, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(async () => undefined, {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(async () => undefined, {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(async () => undefined, {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(async () => undefined, {type: 'directory'}));

expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop));
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {type: 'directory'}));

expectType<string | undefined>(findUp.sync('unicorn.png'));
expectType<string | undefined>(findUp.sync('unicorn.png', {cwd: ''}));
Expand All @@ -35,9 +56,19 @@ expectType<string | undefined>(findUp.sync(['rainbow.png', 'unicorn.png'], {type

expectType<string | undefined>(findUp.sync(() => 'unicorn.png'));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {cwd: ''}));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {allowSymlinks: true}));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {allowSymlinks: false}));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {type: 'file'}));
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {type: 'directory'}));
expectType<string | undefined>(findUp.sync(() => undefined));
expectType<string | undefined>(findUp.sync(() => undefined, {cwd: ''}));
expectType<string | undefined>(findUp.sync(() => undefined, {allowSymlinks: true}));
expectType<string | undefined>(findUp.sync(() => undefined, {allowSymlinks: false}));
expectType<string | undefined>(findUp.sync(() => undefined, {type: 'file'}));
expectType<string | undefined>(findUp.sync(() => undefined, {type: 'directory'}));
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop));
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {cwd: ''}));
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'file'}));
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'directory'}));

expectType<Symbol>(findUp.stop);
4 changes: 2 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const findUp = require('find-up');
console.log(await findUp(async (directory) => {
const hasUnicorns = await pathExists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}});
}}, {type: 'directory'});
//=> '/Users/sindresorhus'
})();
```
Expand Down Expand Up @@ -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.
#### options
Expand Down
32 changes: 16 additions & 16 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,27 +360,27 @@ test('async (matcher function)', async t => {
t.is(await findUp(directory => {
t.is(directory, cwd);
return directory;
}), cwd);
}, {type: 'directory'}), cwd);

t.is(await findUp(() => {
return '.';
}), cwd);
}, {type: 'directory'}), cwd);

t.is(await findUp(async () => {
return 'foo.txt';
}), path.join(cwd, 'foo.txt'));
return 'package.json';
}), path.join(cwd, 'package.json'));

t.is(await findUp(() => {
return '..';
}), path.join(cwd, '..'));
}, {type: 'directory'}), path.join(cwd, '..'));

t.is(await findUp(directory => {
return (directory !== cwd) && directory;
}), path.join(cwd, '..'));
}, {type: 'directory'}), path.join(cwd, '..'));

t.is(await findUp(directory => {
return (directory !== cwd) && 'foo.txt';
}), path.join(cwd, '..', 'foo.txt'));
return (directory === cwd) && 'package.json';
}, {cwd: absolute.fixtureDirectory}), absolute.packageJson);
});

test('async (not found, matcher function)', async t => {
Expand Down Expand Up @@ -442,27 +442,27 @@ test('sync (matcher function)', t => {
t.is(findUp.sync(directory => {
t.is(directory, cwd);
return directory;
}), cwd);
}, {type: 'directory'}), cwd);

t.is(findUp.sync(() => {
return '.';
}), cwd);
}, {type: 'directory'}), cwd);

t.is(findUp.sync(() => {
return 'foo.txt';
}), path.join(cwd, 'foo.txt'));
return 'package.json';
}), path.join(cwd, 'package.json'));

t.is(findUp.sync(() => {
return '..';
}), path.join(cwd, '..'));
}, {type: 'directory'}), path.join(cwd, '..'));

t.is(findUp.sync(directory => {
return (directory !== cwd) && directory;
}), path.join(cwd, '..'));
}, {type: 'directory'}), path.join(cwd, '..'));

t.is(findUp.sync(directory => {
return (directory !== cwd) && 'foo.txt';
}), path.join(cwd, '..', 'foo.txt'));
return (directory === cwd) && 'package.json';
}, {cwd: absolute.fixtureDirectory}), absolute.packageJson);
});

test('sync (not found, matcher function)', t => {
Expand Down

0 comments on commit 43cbbf9

Please sign in to comment.