Skip to content

Commit 43cbbf9

Browse files
coreyfarrellsindresorhus
authored andcommitted
Enable type/allowSymlink matching for return value of matcher function (#42)
1 parent da1b331 commit 43cbbf9

File tree

5 files changed

+79
-35
lines changed

5 files changed

+79
-35
lines changed

index.d.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@ declare const stop: unique symbol;
55
declare namespace findUp {
66
interface Options extends LocatePathOptions {}
77

8-
interface MatcherOptions {
9-
/**
10-
Directory to start from.
11-
12-
@default process.cwd()
13-
*/
14-
readonly cwd?: string;
15-
}
16-
178
type StopSymbol = typeof stop;
189

1910
type Match = string | StopSymbol | undefined;
@@ -57,7 +48,7 @@ declare const findUp: {
5748
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
5849
@returns The first path found or `undefined` if none could be found.
5950
*/
60-
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.MatcherOptions): Promise<string | undefined>;
51+
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;
6152

6253
/**
6354
Synchronously find a file or directory by walking up parent directories.
@@ -73,7 +64,7 @@ declare const findUp: {
7364
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
7465
@returns The first path found or `undefined` if none could be found.
7566
*/
76-
sync(matcher: (directory: string) => findUp.Match, options?: findUp.MatcherOptions): string | undefined;
67+
sync(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;
7768

7869
/**
7970
Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.

index.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,23 @@ module.exports = async (name, options = {}) => {
99
const {root} = path.parse(directory);
1010
const paths = [].concat(name);
1111

12+
const runMatcher = async locateOptions => {
13+
if (typeof name !== 'function') {
14+
return locatePath(paths, locateOptions);
15+
}
16+
17+
const foundPath = await name(locateOptions.cwd);
18+
if (typeof foundPath === 'string') {
19+
return locatePath([foundPath], locateOptions);
20+
}
21+
22+
return foundPath;
23+
};
24+
1225
// eslint-disable-next-line no-constant-condition
1326
while (true) {
1427
// eslint-disable-next-line no-await-in-loop
15-
const foundPath = await (typeof name === 'function' ?
16-
name(directory) :
17-
locatePath(paths, {...options, cwd: directory}));
28+
const foundPath = await runMatcher({...options, cwd: directory});
1829

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

51+
const runMatcher = locateOptions => {
52+
if (typeof name !== 'function') {
53+
return locatePath.sync(paths, locateOptions);
54+
}
55+
56+
const foundPath = name(locateOptions.cwd);
57+
if (typeof foundPath === 'string') {
58+
return locatePath.sync([foundPath], locateOptions);
59+
}
60+
61+
return foundPath;
62+
};
63+
4064
// eslint-disable-next-line no-constant-condition
4165
while (true) {
42-
const foundPath = typeof name === 'function' ?
43-
name(directory) :
44-
locatePath.sync(paths, {...options, cwd: directory});
66+
const foundPath = runMatcher({...options, cwd: directory});
4567

4668
if (foundPath === stop) {
4769
return;

index.test-d.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,37 @@ expectError(findUp(['rainbow.png', 'unicorn.png'], {concurrency: 1}))
1313

1414
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png'));
1515
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {cwd: ''}));
16+
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {allowSymlinks: true}));
17+
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {allowSymlinks: false}));
18+
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {type: 'file'}));
19+
expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {type: 'directory'}));
1620
expectType<Promise<string | undefined>>(findUp(() => undefined));
1721
expectType<Promise<string | undefined>>(findUp(() => undefined, {cwd: ''}));
22+
expectType<Promise<string | undefined>>(findUp(() => undefined, {allowSymlinks: true}));
23+
expectType<Promise<string | undefined>>(findUp(() => undefined, {allowSymlinks: false}));
24+
expectType<Promise<string | undefined>>(findUp(() => undefined, {type: 'file'}));
25+
expectType<Promise<string | undefined>>(findUp(() => undefined, {type: 'directory'}));
1826
expectType<Promise<string | undefined>>(findUp((): findUp.StopSymbol => findUp.stop));
1927
expectType<Promise<string | undefined>>(findUp((): findUp.StopSymbol => findUp.stop, {cwd: ''}));
2028
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png'));
2129
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {cwd: ''}));
30+
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {allowSymlinks: true}));
31+
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {allowSymlinks: false}));
32+
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {type: 'file'}));
33+
expectType<Promise<string | undefined>>(findUp(async () => 'unicorn.png', {type: 'directory'}));
2234
expectType<Promise<string | undefined>>(findUp(async () => undefined));
2335
expectType<Promise<string | undefined>>(findUp(async () => undefined, {cwd: ''}));
36+
expectType<Promise<string | undefined>>(findUp(async () => undefined, {allowSymlinks: true}));
37+
expectType<Promise<string | undefined>>(findUp(async () => undefined, {allowSymlinks: false}));
38+
expectType<Promise<string | undefined>>(findUp(async () => undefined, {type: 'file'}));
39+
expectType<Promise<string | undefined>>(findUp(async () => undefined, {type: 'directory'}));
40+
2441
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop));
2542
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {cwd: ''}));
43+
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {allowSymlinks: true}));
44+
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {allowSymlinks: false}));
45+
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {type: 'file'}));
46+
expectType<Promise<string | undefined>>(findUp(async (): Promise<findUp.StopSymbol> => findUp.stop, {type: 'directory'}));
2647

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

3657
expectType<string | undefined>(findUp.sync(() => 'unicorn.png'));
3758
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {cwd: ''}));
59+
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {allowSymlinks: true}));
60+
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {allowSymlinks: false}));
61+
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {type: 'file'}));
62+
expectType<string | undefined>(findUp.sync(() => 'unicorn.png', {type: 'directory'}));
3863
expectType<string | undefined>(findUp.sync(() => undefined));
3964
expectType<string | undefined>(findUp.sync(() => undefined, {cwd: ''}));
65+
expectType<string | undefined>(findUp.sync(() => undefined, {allowSymlinks: true}));
66+
expectType<string | undefined>(findUp.sync(() => undefined, {allowSymlinks: false}));
67+
expectType<string | undefined>(findUp.sync(() => undefined, {type: 'file'}));
68+
expectType<string | undefined>(findUp.sync(() => undefined, {type: 'directory'}));
4069
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop));
4170
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {cwd: ''}));
71+
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'file'}));
72+
expectType<string | undefined>(findUp.sync((): findUp.StopSymbol => findUp.stop, {type: 'directory'}));
4273

4374
expectType<Symbol>(findUp.stop);

readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const findUp = require('find-up');
5454
console.log(await findUp(async (directory) => {
5555
const hasUnicorns = await pathExists(path.join(directory, 'unicorn.png'));
5656
return hasUnicorns && directory;
57-
}});
57+
}}, {type: 'directory'});
5858
//=> '/Users/sindresorhus'
5959
})();
6060
```
@@ -93,7 +93,7 @@ Type: `Function`
9393
9494
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.
9595
96-
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.
96+
When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path.
9797
9898
#### options
9999

test.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -360,27 +360,27 @@ test('async (matcher function)', async t => {
360360
t.is(await findUp(directory => {
361361
t.is(directory, cwd);
362362
return directory;
363-
}), cwd);
363+
}, {type: 'directory'}), cwd);
364364

365365
t.is(await findUp(() => {
366366
return '.';
367-
}), cwd);
367+
}, {type: 'directory'}), cwd);
368368

369369
t.is(await findUp(async () => {
370-
return 'foo.txt';
371-
}), path.join(cwd, 'foo.txt'));
370+
return 'package.json';
371+
}), path.join(cwd, 'package.json'));
372372

373373
t.is(await findUp(() => {
374374
return '..';
375-
}), path.join(cwd, '..'));
375+
}, {type: 'directory'}), path.join(cwd, '..'));
376376

377377
t.is(await findUp(directory => {
378378
return (directory !== cwd) && directory;
379-
}), path.join(cwd, '..'));
379+
}, {type: 'directory'}), path.join(cwd, '..'));
380380

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

386386
test('async (not found, matcher function)', async t => {
@@ -442,27 +442,27 @@ test('sync (matcher function)', t => {
442442
t.is(findUp.sync(directory => {
443443
t.is(directory, cwd);
444444
return directory;
445-
}), cwd);
445+
}, {type: 'directory'}), cwd);
446446

447447
t.is(findUp.sync(() => {
448448
return '.';
449-
}), cwd);
449+
}, {type: 'directory'}), cwd);
450450

451451
t.is(findUp.sync(() => {
452-
return 'foo.txt';
453-
}), path.join(cwd, 'foo.txt'));
452+
return 'package.json';
453+
}), path.join(cwd, 'package.json'));
454454

455455
t.is(findUp.sync(() => {
456456
return '..';
457-
}), path.join(cwd, '..'));
457+
}, {type: 'directory'}), path.join(cwd, '..'));
458458

459459
t.is(findUp.sync(directory => {
460460
return (directory !== cwd) && directory;
461-
}), path.join(cwd, '..'));
461+
}, {type: 'directory'}), path.join(cwd, '..'));
462462

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

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

0 commit comments

Comments
 (0)