Skip to content

Commit

Permalink
Add stopAt option (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
vast committed Sep 26, 2021
1 parent ace3d10 commit b3b3b00
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 5 deletions.
13 changes: 10 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/unified-signatures */
import {Options} from 'locate-path';
import {Options as LocatePathOptions} from 'locate-path';

/**
Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
Expand All @@ -8,6 +8,15 @@ export const findUpStop: unique symbol;

export type Match = string | typeof findUpStop | undefined;

export interface Options extends LocatePathOptions {
/**
The path to the directory to stop the search before reaching root if there were no matches before the `stopAt` directory.
@default path.parse(cwd).root
*/
readonly stopAt?: string;
}

/**
Find a file or directory by walking up parent directories.
Expand Down Expand Up @@ -137,5 +146,3 @@ console.log(pathExistsSync('/Users/sindresorhus/unicorn.png'));
```
*/
export function pathExistsSync(path: string): boolean;

export {Options} from 'locate-path';
6 changes: 4 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const findUpStop = Symbol('findUpStop');
export async function findUp(name, options = {}) {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const stopAt = path.resolve(directory, options.stopAt || root);
const paths = [name].flat();

const runMatcher = async locateOptions => {
Expand Down Expand Up @@ -34,7 +35,7 @@ export async function findUp(name, options = {}) {
return path.resolve(directory, foundPath);
}

if (directory === root) {
if (directory === stopAt) {
return;
}

Expand All @@ -45,6 +46,7 @@ export async function findUp(name, options = {}) {
export function findUpSync(name, options = {}) {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const stopAt = options.stopAt || root;
const paths = [name].flat();

const runMatcher = locateOptions => {
Expand Down Expand Up @@ -72,7 +74,7 @@ export function findUpSync(name, options = {}) {
return path.resolve(directory, foundPath);
}

if (directory === root) {
if (directory === stopAt) {
return;
}

Expand Down
11 changes: 11 additions & 0 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ expectType<Promise<string | undefined>>(findUp(['rainbow.png', 'unicorn.png'], {
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(['rainbow.png', 'unicorn.png'], {stopAt: 'foo'}));
expectError(findUp(['rainbow.png', 'unicorn.png'], {concurrency: 1}));

expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png'));
Expand All @@ -17,33 +18,39 @@ expectType<Promise<string | undefined>>(findUp(() => 'unicorn.png', {allowSymlin
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(() => 'unicorn.png', {stopAt: 'foo'}));
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(() => undefined, {stopAt: 'foo'}));
expectType<Promise<string | undefined>>(findUp((): typeof findUpStop => findUpStop));
expectType<Promise<string | undefined>>(findUp((): typeof findUpStop => findUpStop, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp((): typeof findUpStop => findUpStop, {stopAt: 'foo'}));
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 () => 'unicorn.png', {stopAt: 'foo'}));
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 () => undefined, {stopAt: 'foo'}));

expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {cwd: ''}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {allowSymlinks: true}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {allowSymlinks: false}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {type: 'file'}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {type: 'directory'}));
expectType<Promise<string | undefined>>(findUp(async (): Promise<typeof findUpStop> => findUpStop, {stopAt: 'foo'}));

expectType<string | undefined>(findUpSync('unicorn.png'));
expectType<string | undefined>(findUpSync('unicorn.png', {cwd: ''}));
Expand All @@ -53,23 +60,27 @@ expectType<string | undefined>(findUpSync(['rainbow.png', 'unicorn.png'], {allow
expectType<string | undefined>(findUpSync(['rainbow.png', 'unicorn.png'], {allowSymlinks: false}));
expectType<string | undefined>(findUpSync(['rainbow.png', 'unicorn.png'], {type: 'file'}));
expectType<string | undefined>(findUpSync(['rainbow.png', 'unicorn.png'], {type: 'directory'}));
expectType<string | undefined>(findUpSync(['rainbow.png', 'unicorn.png'], {stopAt: 'foo'}));

expectType<string | undefined>(findUpSync(() => 'unicorn.png'));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {cwd: ''}));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {allowSymlinks: true}));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {allowSymlinks: false}));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {type: 'file'}));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {type: 'directory'}));
expectType<string | undefined>(findUpSync(() => 'unicorn.png', {stopAt: 'foo'}));
expectType<string | undefined>(findUpSync(() => undefined));
expectType<string | undefined>(findUpSync(() => undefined, {cwd: ''}));
expectType<string | undefined>(findUpSync(() => undefined, {allowSymlinks: true}));
expectType<string | undefined>(findUpSync(() => undefined, {allowSymlinks: false}));
expectType<string | undefined>(findUpSync(() => undefined, {type: 'file'}));
expectType<string | undefined>(findUpSync(() => undefined, {type: 'directory'}));
expectType<string | undefined>(findUpSync(() => undefined, {stopAt: 'foo'}));
expectType<string | undefined>(findUpSync((): typeof findUpStop => findUpStop));
expectType<string | undefined>(findUpSync((): typeof findUpStop => findUpStop, {cwd: ''}));
expectType<string | undefined>(findUpSync((): typeof findUpStop => findUpStop, {type: 'file'}));
expectType<string | undefined>(findUpSync((): typeof findUpStop => findUpStop, {type: 'directory'}));
expectType<string | undefined>(findUpSync((): typeof findUpStop => findUpStop, {stopAt: 'foo'}));

expectType<Promise<boolean>>(pathExists('unicorn.png'));
expectType<boolean>(pathExistsSync('unicorn.png'));
7 changes: 7 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ Default: `true`

Allow symbolic links to match if they point to the chosen path type.

##### stopAt

Type: `string`\
Default: `path.parse(cwd).root`

The path to the directory to stop the search before reaching root if there were no matches before the `stopAt` directory.

### pathExists(path)

Returns a `Promise<boolean>` of whether the path exists.
Expand Down
37 changes: 37 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ absolute.fixtureDirectory = path.join(
);
absolute.baz = path.join(absolute.fixtureDirectory, name.baz);
absolute.qux = path.join(absolute.fixtureDirectory, name.qux);
absolute.fooDir = path.join(absolute.fixtureDirectory, 'foo');
absolute.barDir = path.join(absolute.fixtureDirectory, 'foo', 'bar');
absolute.fileLink = path.join(absolute.fixtureDirectory, name.fileLink);
absolute.directoryLink = path.join(absolute.fixtureDirectory, name.directoryLink);
Expand Down Expand Up @@ -210,6 +211,42 @@ test('sync (cousin file, custom cwd)', t => {
t.is(foundPath, absolute.baz);
});

test('async (cousin file, custom cwd with stopAt)', async t => {
const foundPath = await findUp(name.baz, {
cwd: relative.barDir,
stopAt: absolute.fooDir,
});

t.is(foundPath, undefined);
});

test('sync (cousin file, custom cwd with stopAt)', t => {
const foundPath = findUpSync(name.baz, {
cwd: relative.barDir,
stopAt: absolute.fooDir,
});

t.is(foundPath, undefined);
});

test('async (cousin file, custom cwd, stopAt equal to foundPath)', async t => {
const foundPath = await findUp(name.baz, {
cwd: relative.barDir,
stopAt: absolute.baz,
});

t.is(foundPath, absolute.baz);
});

test('sync (cousin file, custom cwd, stopAt equal to foundPath)', t => {
const foundPath = findUpSync(name.baz, {
cwd: relative.barDir,
stopAt: absolute.baz,
});

t.is(foundPath, absolute.baz);
});

test('async (nested descendant file)', async t => {
const foundPath = await findUp(relative.baz);

Expand Down

0 comments on commit b3b3b00

Please sign in to comment.