You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
2.6 KiB
109 lines
2.6 KiB
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; |
|
|
|
export const findUpStop = Symbol('findUpStop'); |
|
|
|
export async function findUpMultiple(name, options = {}) { |
|
let directory = path.resolve(toPath(options.cwd) || ''); |
|
const {root} = path.parse(directory); |
|
const stopAt = path.resolve(directory, options.stopAt || root); |
|
const limit = options.limit || Number.POSITIVE_INFINITY; |
|
const paths = [name].flat(); |
|
|
|
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; |
|
}; |
|
|
|
const matches = []; |
|
// eslint-disable-next-line no-constant-condition |
|
while (true) { |
|
// eslint-disable-next-line no-await-in-loop |
|
const foundPath = await runMatcher({...options, cwd: directory}); |
|
|
|
if (foundPath === findUpStop) { |
|
break; |
|
} |
|
|
|
if (foundPath) { |
|
matches.push(path.resolve(directory, foundPath)); |
|
} |
|
|
|
if (directory === stopAt || matches.length >= limit) { |
|
break; |
|
} |
|
|
|
directory = path.dirname(directory); |
|
} |
|
|
|
return matches; |
|
} |
|
|
|
export function findUpMultipleSync(name, options = {}) { |
|
let directory = path.resolve(toPath(options.cwd) || ''); |
|
const {root} = path.parse(directory); |
|
const stopAt = options.stopAt || root; |
|
const limit = options.limit || Number.POSITIVE_INFINITY; |
|
const paths = [name].flat(); |
|
|
|
const runMatcher = locateOptions => { |
|
if (typeof name !== 'function') { |
|
return locatePathSync(paths, locateOptions); |
|
} |
|
|
|
const foundPath = name(locateOptions.cwd); |
|
if (typeof foundPath === 'string') { |
|
return locatePathSync([foundPath], locateOptions); |
|
} |
|
|
|
return foundPath; |
|
}; |
|
|
|
const matches = []; |
|
// eslint-disable-next-line no-constant-condition |
|
while (true) { |
|
const foundPath = runMatcher({...options, cwd: directory}); |
|
|
|
if (foundPath === findUpStop) { |
|
break; |
|
} |
|
|
|
if (foundPath) { |
|
matches.push(path.resolve(directory, foundPath)); |
|
} |
|
|
|
if (directory === stopAt || matches.length >= limit) { |
|
break; |
|
} |
|
|
|
directory = path.dirname(directory); |
|
} |
|
|
|
return matches; |
|
} |
|
|
|
export async function findUp(name, options = {}) { |
|
const matches = await findUpMultiple(name, {...options, limit: 1}); |
|
return matches[0]; |
|
} |
|
|
|
export function findUpSync(name, options = {}) { |
|
const matches = findUpMultipleSync(name, {...options, limit: 1}); |
|
return matches[0]; |
|
} |
|
|
|
export { |
|
pathExists, |
|
pathExistsSync, |
|
} from 'path-exists';
|
|
|