209 lines
6.0 KiB
JavaScript
209 lines
6.0 KiB
JavaScript
import process from 'node:process';
|
|
import path from 'node:path';
|
|
import os from 'node:os';
|
|
import fs from 'node:fs';
|
|
import ini from 'ini';
|
|
|
|
const isWindows = process.platform === 'win32';
|
|
|
|
const untildify = pathWithTilde => pathWithTilde && pathWithTilde.startsWith('~') ? path.join(os.homedir(), pathWithTilde.slice(1)) : pathWithTilde;
|
|
|
|
const readConfigValue = (filePath, key) => {
|
|
if (!filePath) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
return ini.parse(fs.readFileSync(filePath, 'utf8'))[key];
|
|
} catch {}
|
|
};
|
|
|
|
const getEnvironmentNpmConfigValue = key => {
|
|
const normalizedKey = `npm_config_${key.replaceAll('-', '_')}`.toLowerCase();
|
|
const environmentKey = Object.keys(process.env).find(name => name.toLowerCase() === normalizedKey);
|
|
return environmentKey ? process.env[environmentKey] : undefined;
|
|
};
|
|
|
|
const getGlobalNpmrc = () => {
|
|
if (isWindows && process.env.APPDATA) {
|
|
// Hardcoded contents of `c:\Program Files\nodejs\node_modules\npm\npmrc`
|
|
return path.join(process.env.APPDATA, '/npm/etc/npmrc');
|
|
}
|
|
|
|
// Homebrew special case: `$(brew --prefix)/lib/node_modules/npm/npmrc`
|
|
if (process.execPath.includes('/Cellar/node')) {
|
|
const homebrewPrefix = process.execPath.slice(0, process.execPath.indexOf('/Cellar/node'));
|
|
return path.join(homebrewPrefix, '/lib/node_modules/npm/npmrc');
|
|
}
|
|
|
|
if (process.execPath.endsWith('/bin/node')) {
|
|
const installDir = path.dirname(path.dirname(process.execPath));
|
|
return path.join(installDir, '/etc/npmrc');
|
|
}
|
|
};
|
|
|
|
const getDefaultNpmPrefix = () => {
|
|
if (isWindows) {
|
|
const {APPDATA} = process.env;
|
|
// `c:\node\node.exe` → `prefix=c:\node\`
|
|
return APPDATA ? path.join(APPDATA, 'npm') : path.dirname(process.execPath);
|
|
}
|
|
|
|
// Homebrew: `/opt/homebrew/Cellar/node/21.0.0/bin/node` → `/opt/homebrew`
|
|
if (process.execPath.includes('/Cellar/node')) {
|
|
return process.execPath.slice(0, process.execPath.indexOf('/Cellar/node'));
|
|
}
|
|
|
|
// `/usr/local/bin/node` → `prefix=/usr/local`
|
|
return path.dirname(path.dirname(process.execPath));
|
|
};
|
|
|
|
const getNpmPrefix = () => {
|
|
const environmentPrefix = getEnvironmentNpmConfigValue('prefix');
|
|
if (environmentPrefix !== undefined) {
|
|
return environmentPrefix;
|
|
}
|
|
|
|
const homePrefix = readConfigValue(path.join(os.homedir(), '.npmrc'), 'prefix');
|
|
if (homePrefix !== undefined) {
|
|
return homePrefix;
|
|
}
|
|
|
|
if (process.env.PREFIX) {
|
|
return process.env.PREFIX;
|
|
}
|
|
|
|
const globalPrefix = readConfigValue(getGlobalNpmrc(), 'prefix');
|
|
if (globalPrefix !== undefined) {
|
|
return globalPrefix;
|
|
}
|
|
|
|
return getDefaultNpmPrefix();
|
|
};
|
|
|
|
const npmPrefix = path.resolve(untildify(getNpmPrefix()));
|
|
|
|
const getYarnHomeDirectory = () => {
|
|
if (process.getuid?.() === 0 && !process.env.FAKEROOTKEY) {
|
|
return '/usr/local/share';
|
|
}
|
|
|
|
return os.homedir();
|
|
};
|
|
|
|
const getYarnDataDirectory = () => {
|
|
if (isWindows) {
|
|
return process.env.LOCALAPPDATA
|
|
? path.join(process.env.LOCALAPPDATA, 'Yarn/Data')
|
|
: path.join(os.homedir(), '.config/yarn');
|
|
}
|
|
|
|
if (process.env.XDG_DATA_HOME) {
|
|
return path.join(process.env.XDG_DATA_HOME, 'yarn');
|
|
}
|
|
|
|
return path.join(getYarnHomeDirectory(), '.config/yarn');
|
|
};
|
|
|
|
const getYarnBinPrefix = () => {
|
|
if (process.env.PREFIX) {
|
|
return process.env.PREFIX;
|
|
}
|
|
|
|
if (isWindows) {
|
|
return process.env.LOCALAPPDATA
|
|
? path.join(process.env.LOCALAPPDATA, 'Yarn')
|
|
: path.join(os.homedir(), '.yarn');
|
|
}
|
|
|
|
return `${process.env.DESTDIR ?? ''}/usr/local`;
|
|
};
|
|
|
|
const globalDirectory = {};
|
|
|
|
globalDirectory.npm = {};
|
|
globalDirectory.npm.prefix = npmPrefix;
|
|
globalDirectory.npm.packages = path.join(npmPrefix, isWindows ? 'node_modules' : 'lib/node_modules');
|
|
globalDirectory.npm.binaries = isWindows ? npmPrefix : path.join(npmPrefix, 'bin');
|
|
|
|
const yarnDataDir = path.resolve(getYarnDataDirectory());
|
|
globalDirectory.yarn = {};
|
|
globalDirectory.yarn.prefix = yarnDataDir;
|
|
globalDirectory.yarn.packages = path.join(yarnDataDir, 'global/node_modules');
|
|
globalDirectory.yarn.binaries = path.join(path.resolve(getYarnBinPrefix()), 'bin');
|
|
|
|
const getPnpmDataDirectory = () => {
|
|
if (process.env.PNPM_HOME) {
|
|
return process.env.PNPM_HOME;
|
|
}
|
|
|
|
if (process.env.XDG_DATA_HOME) {
|
|
return path.join(process.env.XDG_DATA_HOME, 'pnpm');
|
|
}
|
|
|
|
if (process.platform === 'darwin') {
|
|
return path.join(os.homedir(), 'Library/pnpm');
|
|
}
|
|
|
|
if (!isWindows) {
|
|
return path.join(os.homedir(), '.local/share/pnpm');
|
|
}
|
|
|
|
if (process.env.LOCALAPPDATA) {
|
|
return path.join(process.env.LOCALAPPDATA, 'pnpm');
|
|
}
|
|
|
|
return path.join(os.homedir(), '.pnpm');
|
|
};
|
|
|
|
const getPnpmConfigFilePath = () => {
|
|
if (process.env.XDG_CONFIG_HOME) {
|
|
return path.join(process.env.XDG_CONFIG_HOME, 'pnpm', 'rc');
|
|
}
|
|
|
|
if (isWindows) {
|
|
const localConfigHome = process.env.LOCALAPPDATA ?? path.join(os.homedir(), 'AppData', 'Local');
|
|
return path.join(localConfigHome, 'pnpm', 'config', 'rc');
|
|
}
|
|
|
|
if (process.platform === 'darwin') {
|
|
return path.join(os.homedir(), 'Library', 'Preferences', 'pnpm', 'rc');
|
|
}
|
|
|
|
return path.join(os.homedir(), '.config', 'pnpm', 'rc');
|
|
};
|
|
|
|
const getPnpmConfigValue = key => {
|
|
const environmentValue = getEnvironmentNpmConfigValue(key);
|
|
if (environmentValue !== undefined) {
|
|
return environmentValue;
|
|
}
|
|
|
|
const pnpmGlobalValue = readConfigValue(getPnpmConfigFilePath(), key);
|
|
if (pnpmGlobalValue !== undefined) {
|
|
return pnpmGlobalValue;
|
|
}
|
|
|
|
const homeValue = readConfigValue(path.join(os.homedir(), '.npmrc'), key);
|
|
if (homeValue !== undefined) {
|
|
return homeValue;
|
|
}
|
|
|
|
const globalValue = readConfigValue(getGlobalNpmrc(), key);
|
|
if (globalValue !== undefined) {
|
|
return globalValue;
|
|
}
|
|
};
|
|
|
|
const pnpmDataDir = path.resolve(getPnpmDataDirectory());
|
|
const pnpmGlobalDir = getPnpmConfigValue('global-dir');
|
|
const pnpmGlobalBinDir = getPnpmConfigValue('global-bin-dir');
|
|
const resolvedPnpmGlobalDir = path.resolve(untildify(pnpmGlobalDir ?? path.join(pnpmDataDir, 'global')));
|
|
const resolvedPnpmGlobalBinDir = path.resolve(untildify(pnpmGlobalBinDir ?? pnpmDataDir));
|
|
globalDirectory.pnpm = {};
|
|
globalDirectory.pnpm.prefix = pnpmDataDir;
|
|
globalDirectory.pnpm.packages = path.join(resolvedPnpmGlobalDir, '5/node_modules');
|
|
globalDirectory.pnpm.binaries = resolvedPnpmGlobalBinDir;
|
|
|
|
export default globalDirectory;
|