1 | import path from 'node:path';
|
2 | import {locatePath, locatePathSync} from 'locate-path';
|
3 | import {toPath} from 'unicorn-magic';
|
4 |
|
5 | export const findUpStop = Symbol('findUpStop');
|
6 |
|
7 | export 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 |
|
29 | while (true) {
|
30 |
|
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 |
|
51 | export 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 |
|
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 |
|
94 | export async function findUp(name, options = {}) {
|
95 | const matches = await findUpMultiple(name, {...options, limit: 1});
|
96 | return matches[0];
|
97 | }
|
98 |
|
99 | export function findUpSync(name, options = {}) {
|
100 | const matches = findUpMultipleSync(name, {...options, limit: 1});
|
101 | return matches[0];
|
102 | }
|
103 |
|
104 | export {
|
105 | pathExists,
|
106 | pathExistsSync,
|
107 | } from 'path-exists';
|