LendAndRegret/node_modules/global-directory/index.js
2026-05-02 17:27:43 +08:00

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;