index.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. 'use strict';
  2. const path = require('path');
  3. const os = require('os');
  4. const fs = require('fs');
  5. const ini = require('ini');
  6. const isWindows = process.platform === 'win32';
  7. const readRc = filePath => {
  8. try {
  9. return ini.parse(fs.readFileSync(filePath, 'utf8')).prefix;
  10. } catch {}
  11. };
  12. const getEnvNpmPrefix = () => {
  13. // TODO: Remove the `.reduce` call.
  14. // eslint-disable-next-line unicorn/no-array-reduce
  15. return Object.keys(process.env).reduce((prefix, name) => {
  16. return /^npm_config_prefix$/i.test(name) ? process.env[name] : prefix;
  17. }, undefined);
  18. };
  19. const getGlobalNpmrc = () => {
  20. if (isWindows && process.env.APPDATA) {
  21. // Hardcoded contents of `c:\Program Files\nodejs\node_modules\npm\npmrc`
  22. return path.join(process.env.APPDATA, '/npm/etc/npmrc');
  23. }
  24. // Homebrew special case: `$(brew --prefix)/lib/node_modules/npm/npmrc`
  25. if (process.execPath.includes('/Cellar/node')) {
  26. const homebrewPrefix = process.execPath.slice(0, process.execPath.indexOf('/Cellar/node'));
  27. return path.join(homebrewPrefix, '/lib/node_modules/npm/npmrc');
  28. }
  29. if (process.execPath.endsWith('/bin/node')) {
  30. const installDir = path.dirname(path.dirname(process.execPath));
  31. return path.join(installDir, '/etc/npmrc');
  32. }
  33. };
  34. const getDefaultNpmPrefix = () => {
  35. if (isWindows) {
  36. // `c:\node\node.exe` → `prefix=c:\node\`
  37. return path.dirname(process.execPath);
  38. }
  39. // `/usr/local/bin/node` → `prefix=/usr/local`
  40. return path.dirname(path.dirname(process.execPath));
  41. };
  42. const getNpmPrefix = () => {
  43. const envPrefix = getEnvNpmPrefix();
  44. if (envPrefix) {
  45. return envPrefix;
  46. }
  47. const homePrefix = readRc(path.join(os.homedir(), '.npmrc'));
  48. if (homePrefix) {
  49. return homePrefix;
  50. }
  51. if (process.env.PREFIX) {
  52. return process.env.PREFIX;
  53. }
  54. const globalPrefix = readRc(getGlobalNpmrc());
  55. if (globalPrefix) {
  56. return globalPrefix;
  57. }
  58. return getDefaultNpmPrefix();
  59. };
  60. const npmPrefix = path.resolve(getNpmPrefix());
  61. const getYarnWindowsDirectory = () => {
  62. if (isWindows && process.env.LOCALAPPDATA) {
  63. const dir = path.join(process.env.LOCALAPPDATA, 'Yarn');
  64. if (fs.existsSync(dir)) {
  65. return dir;
  66. }
  67. }
  68. return false;
  69. };
  70. const getYarnPrefix = () => {
  71. if (process.env.PREFIX) {
  72. return process.env.PREFIX;
  73. }
  74. const windowsPrefix = getYarnWindowsDirectory();
  75. if (windowsPrefix) {
  76. return windowsPrefix;
  77. }
  78. const configPrefix = path.join(os.homedir(), '.config/yarn');
  79. if (fs.existsSync(configPrefix)) {
  80. return configPrefix;
  81. }
  82. const homePrefix = path.join(os.homedir(), '.yarn-config');
  83. if (fs.existsSync(homePrefix)) {
  84. return homePrefix;
  85. }
  86. // Yarn supports the npm conventions but the inverse is not true
  87. return npmPrefix;
  88. };
  89. exports.npm = {};
  90. exports.npm.prefix = npmPrefix;
  91. exports.npm.packages = path.join(npmPrefix, isWindows ? 'node_modules' : 'lib/node_modules');
  92. exports.npm.binaries = isWindows ? npmPrefix : path.join(npmPrefix, 'bin');
  93. const yarnPrefix = path.resolve(getYarnPrefix());
  94. exports.yarn = {};
  95. exports.yarn.prefix = yarnPrefix;
  96. exports.yarn.packages = path.join(yarnPrefix, getYarnWindowsDirectory() ? 'Data/global/node_modules' : 'global/node_modules');
  97. exports.yarn.binaries = path.join(exports.yarn.packages, '.bin');