index.js 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import process from 'node:process';
  2. import path from 'node:path';
  3. import pathKey from 'path-key';
  4. import {toPath, traversePathUp} from 'unicorn-magic';
  5. export const npmRunPath = ({
  6. cwd = process.cwd(),
  7. path: pathOption = process.env[pathKey()],
  8. preferLocal = true,
  9. execPath = process.execPath,
  10. addExecPath = true,
  11. } = {}) => {
  12. const cwdPath = path.resolve(toPath(cwd));
  13. const result = [];
  14. const pathParts = pathOption.split(path.delimiter);
  15. if (preferLocal) {
  16. applyPreferLocal(result, pathParts, cwdPath);
  17. }
  18. if (addExecPath) {
  19. applyExecPath(result, pathParts, execPath, cwdPath);
  20. }
  21. return pathOption === '' || pathOption === path.delimiter
  22. ? `${result.join(path.delimiter)}${pathOption}`
  23. : [...result, pathOption].join(path.delimiter);
  24. };
  25. const applyPreferLocal = (result, pathParts, cwdPath) => {
  26. for (const directory of traversePathUp(cwdPath)) {
  27. const pathPart = path.join(directory, 'node_modules/.bin');
  28. if (!pathParts.includes(pathPart)) {
  29. result.push(pathPart);
  30. }
  31. }
  32. };
  33. // Ensure the running `node` binary is used
  34. const applyExecPath = (result, pathParts, execPath, cwdPath) => {
  35. const pathPart = path.resolve(cwdPath, toPath(execPath), '..');
  36. if (!pathParts.includes(pathPart)) {
  37. result.push(pathPart);
  38. }
  39. };
  40. export const npmRunPathEnv = ({env = process.env, ...options} = {}) => {
  41. env = {...env};
  42. const pathName = pathKey({env});
  43. options.path = env[pathName];
  44. env[pathName] = npmRunPath(options);
  45. return env;
  46. };