diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 85a0b14..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: sindresorhus -tidelift: npm/find-up diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5735f77..5e39333 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,8 +16,8 @@ jobs: - macos-latest - windows-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.d.ts b/index.d.ts index 64f4049..95029b4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,5 +1,4 @@ -/* eslint-disable @typescript-eslint/unified-signatures */ -import {Options as LocatePathOptions} from 'locate-path'; +import {type Options as LocatePathOptions} from 'locate-path'; /** Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`. @@ -8,14 +7,14 @@ export const findUpStop: unique symbol; export type Match = string | typeof findUpStop | undefined; -export interface Options extends LocatePathOptions { +export type Options = { /** - The path to the directory to stop the search before reaching root if there were no matches before the `stopAt` directory. + A directory path where the search halts if no matches are found before reaching this point. - @default path.parse(cwd).root + Default: Root directory */ readonly stopAt?: string; -} +} & LocatePathOptions; /** Find a file or directory by walking up parent directories. diff --git a/index.js b/index.js index e0b8004..c49fef0 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,14 @@ import path from 'node:path'; -import {fileURLToPath} from 'node:url'; import {locatePath, locatePathSync} from 'locate-path'; - -const toPath = urlOrPath => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath; +import {toPath} from 'unicorn-magic'; export const findUpStop = Symbol('findUpStop'); export async function findUpMultiple(name, options = {}) { - let directory = path.resolve(toPath(options.cwd) || ''); + let directory = path.resolve(toPath(options.cwd) ?? ''); const {root} = path.parse(directory); const stopAt = path.resolve(directory, toPath(options.stopAt ?? root)); - const limit = options.limit || Number.POSITIVE_INFINITY; + const limit = options.limit ?? Number.POSITIVE_INFINITY; const paths = [name].flat(); const runMatcher = async locateOptions => { @@ -51,10 +49,10 @@ export async function findUpMultiple(name, options = {}) { } export function findUpMultipleSync(name, options = {}) { - let directory = path.resolve(toPath(options.cwd) || ''); + let directory = path.resolve(toPath(options.cwd) ?? ''); const {root} = path.parse(directory); const stopAt = path.resolve(directory, toPath(options.stopAt) ?? root); - const limit = options.limit || Number.POSITIVE_INFINITY; + const limit = options.limit ?? Number.POSITIVE_INFINITY; const paths = [name].flat(); const runMatcher = locateOptions => { diff --git a/index.test-d.ts b/index.test-d.ts index 4d154a5..9152413 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,5 +1,13 @@ import {expectType, expectError} from 'tsd'; -import {findUp, findUpSync, findUpMultiple, findUpMultipleSync, findUpStop, pathExists, pathExistsSync} from './index.js'; +import { + findUp, + findUpSync, + findUpMultiple, + findUpMultipleSync, + findUpStop, + pathExists, + pathExistsSync, +} from './index.js'; expectType>(findUp('unicorn.png')); expectType>(findUp('unicorn.png', {cwd: ''})); diff --git a/package.json b/package.json index 030b143..9129af6 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,13 @@ "url": "https://sindresorhus.com" }, "type": "module", - "exports": "./index.js", + "exports": { + "types": "./index.d.ts", + "default": "./index.js" + }, + "sideEffects": false, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "scripts": { "test": "xo && ava && tsd" @@ -43,14 +47,15 @@ "path" ], "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" }, "devDependencies": { - "ava": "^3.15.0", + "ava": "^5.3.1", "is-path-inside": "^4.0.0", - "tempy": "^3.0.0", - "tsd": "^0.17.0", - "xo": "^0.44.0" + "tempy": "^3.1.0", + "tsd": "^0.29.0", + "xo": "^0.56.0" } } diff --git a/readme.md b/readme.md index 488ac61..f7c40f4 100644 --- a/readme.md +++ b/readme.md @@ -4,8 +4,8 @@ ## Install -``` -$ npm install find-up +```sh +npm install find-up ``` ## Usage @@ -45,7 +45,7 @@ console.log(await findUp(async directory => { ### findUp(name, options?) ### findUp(matcher, options?) -Returns a `Promise` for either the path or `undefined` if it couldn't be found. +Returns a `Promise` for either the path or `undefined` if it could not be found. ### findUp([...name], options?) @@ -63,7 +63,7 @@ Returns a `Promise` for either an array of the first paths found (by respecting ### findUpSync(name, options?) ### findUpSync(matcher, options?) -Returns a path or `undefined` if it couldn't be found. +Returns a path or `undefined` if it could not be found. ### findUpSync([...name], options?) @@ -107,9 +107,9 @@ The directory to start from. Type: `string`\ Default: `'file'`\ -Values: `'file'` `'directory'` +Values: `'file' | 'directory'` -The type of paths that can match. +The type of path to match. ##### allowSymlinks @@ -120,10 +120,10 @@ Allow symbolic links to match if they point to the chosen path type. ##### stopAt -Type: `string`\ -Default: `path.parse(cwd).root` +Type: `URL | string`\ +Default: Root directory -The path to the directory to stop the search before reaching root if there were no matches before the `stopAt` directory. +A directory path where the search halts if no matches are found before reaching this point. ### pathExists(path) @@ -155,18 +155,6 @@ await findUp(directory => { ## Related - [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module -- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file +- [package-up](https://github.com/sindresorhus/package-up) - Find the closest package.json file - [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package - [resolve-from](https://github.com/sindresorhus/resolve-from) - Resolve the path of a module like `require.resolve()` but from a given path - ---- - -
- - Get professional support for 'find-up' with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
diff --git a/test.js b/test.js index 69fd1c3..bc5d06d 100644 --- a/test.js +++ b/test.js @@ -6,7 +6,15 @@ import {fileURLToPath, pathToFileURL} from 'node:url'; import test from 'ava'; import isPathInside from 'is-path-inside'; import {temporaryDirectory} from 'tempy'; -import {findUp, findUpSync, findUpMultiple, findUpMultipleSync, findUpStop, pathExists, pathExistsSync} from './index.js'; +import { + findUp, + findUpSync, + findUpMultiple, + findUpMultipleSync, + findUpStop, + pathExists, + pathExistsSync, +} from './index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -356,90 +364,6 @@ test('sync (absolute directory)', t => { t.is(filePath, absolute.barDir); }); -test('async multiple (child file)', async t => { - const filePaths = await findUpMultiple(name.qux, {cwd: relative.barDir}); - - t.deepEqual(filePaths, [absolute.barDirQux, absolute.qux]); -}); - -test('sync multiple (child file)', t => { - const filePaths = findUpMultipleSync(name.qux, {cwd: relative.barDir}); - - t.deepEqual(filePaths, [absolute.barDirQux, absolute.qux]); -}); - -test('async multiple (child directory)', async t => { - const foundPath = await findUpMultiple(name.fixtureDirectory, {type: 'directory'}); - - t.deepEqual(foundPath, [absolute.fixtureDirectory]); -}); - -test('sync multiple (child directory)', t => { - const foundPath = findUpMultipleSync(name.fixtureDirectory, {type: 'directory'}); - - t.deepEqual(foundPath, [absolute.fixtureDirectory]); -}); - -test('async multiple (child file, array)', async t => { - const filePaths = await findUpMultiple([name.baz, name.qux], {cwd: relative.barDir}); - - t.deepEqual(filePaths, [absolute.barDirQux, absolute.baz]); -}); - -test('sync multiple (child file, array)', t => { - const filePaths = findUpMultipleSync([name.baz, name.qux], {cwd: relative.barDir}); - - t.deepEqual(filePaths, [absolute.barDirQux, absolute.baz]); -}); - -test('async multiple (child directory, custom cwd, array)', async t => { - const foundPath = await findUpMultiple([name.fixtureDirectory, name.fooDirectory], { - cwd: absolute.barDir, - type: 'directory', - }); - - t.deepEqual(foundPath, [absolute.fooDir, absolute.fixtureDirectory]); -}); - -test('sync multiple (child directory, custom cwd, array)', t => { - const foundPath = findUpMultipleSync([name.fixtureDirectory, name.fooDirectory], { - cwd: absolute.barDir, - type: 'directory', - }); - - t.deepEqual(foundPath, [absolute.fooDir, absolute.fixtureDirectory]); -}); - -test('async multiple (child file with stopAt)', async t => { - const filePaths = await findUpMultiple(name.qux, { - cwd: relative.barDir, - stopAt: absolute.fooDir, - }); - - t.deepEqual(filePaths, [absolute.barDirQux]); -}); - -test('sync multiple (child file with stopAt)', t => { - const filePaths = findUpMultipleSync(name.qux, { - cwd: relative.barDir, - stopAt: absolute.fooDir, - }); - - t.deepEqual(filePaths, [absolute.barDirQux]); -}); - -test('async multiple (not found, child file)', async t => { - const filePaths = await findUpMultiple('somenonexistentfile.js', {cwd: relative.barDir}); - - t.deepEqual(filePaths, []); -}); - -test('sync multiple (not found, child file)', t => { - const filePaths = findUpMultipleSync('somenonexistentfile.js', {cwd: relative.barDir}); - - t.deepEqual(filePaths, []); -}); - test('async (not found, absolute file)', async t => { const filePath = await findUp(path.resolve('somenonexistentfile.js')); @@ -500,6 +424,16 @@ test('sync (not found, custom cwd)', t => { t.is(foundPath, undefined); }); +test('async (dot file)', async t => { + const foundPath = await findUp(name.dotDirectory, {type: 'directory'}); + t.is(foundPath, absolute.dotDirectory); +}); + +test('sync (dot file)', async t => { + const foundPath = await findUp(name.dotDirectory, {type: 'directory'}); + t.is(foundPath, absolute.dotDirectory); +}); + test('async (matcher function)', async t => { const cwd = process.cwd(); @@ -655,12 +589,86 @@ test('sync (check if path exists)', t => { t.false(pathExistsSync('fake')); }); -test('async (dot file)', async t => { - const foundPath = await findUp(name.dotDirectory, {type: 'directory'}); - t.is(foundPath, absolute.dotDirectory); +test('async multiple (child file)', async t => { + const filePaths = await findUpMultiple(name.qux, {cwd: relative.barDir}); + + t.deepEqual(filePaths, [absolute.barDirQux, absolute.qux]); }); -test('sync (dot file)', async t => { - const foundPath = await findUp(name.dotDirectory, {type: 'directory'}); - t.is(foundPath, absolute.dotDirectory); +test('sync multiple (child file)', t => { + const filePaths = findUpMultipleSync(name.qux, {cwd: relative.barDir}); + + t.deepEqual(filePaths, [absolute.barDirQux, absolute.qux]); +}); + +test('async multiple (child directory)', async t => { + const foundPath = await findUpMultiple(name.fixtureDirectory, {type: 'directory'}); + + t.deepEqual(foundPath, [absolute.fixtureDirectory]); +}); + +test('sync multiple (child directory)', t => { + const foundPath = findUpMultipleSync(name.fixtureDirectory, {type: 'directory'}); + + t.deepEqual(foundPath, [absolute.fixtureDirectory]); +}); + +test('async multiple (child file, array)', async t => { + const filePaths = await findUpMultiple([name.baz, name.qux], {cwd: relative.barDir}); + + t.deepEqual(filePaths, [absolute.barDirQux, absolute.baz]); +}); + +test('sync multiple (child file, array)', t => { + const filePaths = findUpMultipleSync([name.baz, name.qux], {cwd: relative.barDir}); + + t.deepEqual(filePaths, [absolute.barDirQux, absolute.baz]); +}); + +test('async multiple (child directory, custom cwd, array)', async t => { + const foundPath = await findUpMultiple([name.fixtureDirectory, name.fooDirectory], { + cwd: absolute.barDir, + type: 'directory', + }); + + t.deepEqual(foundPath, [absolute.fooDir, absolute.fixtureDirectory]); +}); + +test('sync multiple (child directory, custom cwd, array)', t => { + const foundPath = findUpMultipleSync([name.fixtureDirectory, name.fooDirectory], { + cwd: absolute.barDir, + type: 'directory', + }); + + t.deepEqual(foundPath, [absolute.fooDir, absolute.fixtureDirectory]); +}); + +test('async multiple (child file with stopAt)', async t => { + const filePaths = await findUpMultiple(name.qux, { + cwd: relative.barDir, + stopAt: absolute.fooDir, + }); + + t.deepEqual(filePaths, [absolute.barDirQux]); +}); + +test('sync multiple (child file with stopAt)', t => { + const filePaths = findUpMultipleSync(name.qux, { + cwd: relative.barDir, + stopAt: absolute.fooDir, + }); + + t.deepEqual(filePaths, [absolute.barDirQux]); +}); + +test('async multiple (not found, child file)', async t => { + const filePaths = await findUpMultiple('somenonexistentfile.js', {cwd: relative.barDir}); + + t.deepEqual(filePaths, []); +}); + +test('sync multiple (not found, child file)', t => { + const filePaths = findUpMultipleSync('somenonexistentfile.js', {cwd: relative.barDir}); + + t.deepEqual(filePaths, []); });