index.js 2.6 KB

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