UNPKG

2.62 kBJavaScriptView Raw
1import path from 'node:path';
2import {locatePath, locatePathSync} from 'locate-path';
3import {toPath} from 'unicorn-magic';
4
5export const findUpStop = Symbol('findUpStop');
6
7export async function findUpMultiple(name, options = {}) {
8 let directory = path.resolve(toPath(options.cwd) ?? '');
9 const {root} = path.parse(directory);
10 const stopAt = path.resolve(directory, toPath(options.stopAt ?? root));
11 const limit = options.limit ?? Number.POSITIVE_INFINITY;
12 const paths = [name].flat();
13
14 const runMatcher = async locateOptions => {
15 if (typeof name !== 'function') {
16 return locatePath(paths, locateOptions);
17 }
18
19 const foundPath = await name(locateOptions.cwd);
20 if (typeof foundPath === 'string') {
21 return locatePath([foundPath], locateOptions);
22 }
23
24 return foundPath;
25 };
26
27 const matches = [];
28 // eslint-disable-next-line no-constant-condition
29 while (true) {
30 // eslint-disable-next-line no-await-in-loop
31 const foundPath = await runMatcher({...options, cwd: directory});
32
33 if (foundPath === findUpStop) {
34 break;
35 }
36
37 if (foundPath) {
38 matches.push(path.resolve(directory, foundPath));
39 }
40
41 if (directory === stopAt || matches.length >= limit) {
42 break;
43 }
44
45 directory = path.dirname(directory);
46 }
47
48 return matches;
49}
50
51export function findUpMultipleSync(name, options = {}) {
52 let directory = path.resolve(toPath(options.cwd) ?? '');
53 const {root} = path.parse(directory);
54 const stopAt = path.resolve(directory, toPath(options.stopAt) ?? root);
55 const limit = options.limit ?? Number.POSITIVE_INFINITY;
56 const paths = [name].flat();
57
58 const runMatcher = locateOptions => {
59 if (typeof name !== 'function') {
60 return locatePathSync(paths, locateOptions);
61 }
62
63 const foundPath = name(locateOptions.cwd);
64 if (typeof foundPath === 'string') {
65 return locatePathSync([foundPath], locateOptions);
66 }
67
68 return foundPath;
69 };
70
71 const matches = [];
72 // eslint-disable-next-line no-constant-condition
73 while (true) {
74 const foundPath = runMatcher({...options, cwd: directory});
75
76 if (foundPath === findUpStop) {
77 break;
78 }
79
80 if (foundPath) {
81 matches.push(path.resolve(directory, foundPath));
82 }
83
84 if (directory === stopAt || matches.length >= limit) {
85 break;
86 }
87
88 directory = path.dirname(directory);
89 }
90
91 return matches;
92}
93
94export async function findUp(name, options = {}) {
95 const matches = await findUpMultiple(name, {...options, limit: 1});
96 return matches[0];
97}
98
99export function findUpSync(name, options = {}) {
100 const matches = findUpMultipleSync(name, {...options, limit: 1});
101 return matches[0];
102}
103
104export {
105 pathExists,
106 pathExistsSync,
107} from 'path-exists';