UNPKG

@reliverse/rse

Version:

@reliverse/rse is your all-in-one companion for bootstrapping and improving any kind of projects (especially web apps built with frameworks like Next.js) — whether you're kicking off something new or upgrading an existing app. It is also a little AI-power

188 lines (187 loc) 5.91 kB
import path from "@reliverse/pathkit"; import fs from "@reliverse/relifso"; import { execa } from "execa"; const cache = /* @__PURE__ */ new Map(); async function pathExists(p) { try { await fs.access(p); return true; } catch { return false; } } async function checkPMVersion(pm, includeGlobalBun = true) { if (pm === "bun" && !includeGlobalBun) return null; const cacheKey = `has_global_${pm}`; if (cache.has(cacheKey)) { return cache.get(cacheKey); } try { const { stdout } = await execa(pm, ["--version"]); if (/^\d+.\d+.\d+$/.test(stdout)) { cache.set(cacheKey, stdout); return stdout; } } catch (_error) { cache.set(cacheKey, null); } return null; } async function detectLockFile(projectPath) { const cacheKey = `lockfile_${projectPath}`; if (cache.has(cacheKey)) { return cache.get(cacheKey); } const lockFiles = await Promise.all([ pathExists(path.join(projectPath, "yarn.lock")), pathExists(path.join(projectPath, "package-lock.json")), pathExists(path.join(projectPath, "pnpm-lock.yaml")), pathExists(path.join(projectPath, "bun.lock")) ]); let result = null; const [isYarn, isNpm, isPnpm, isBun] = lockFiles; if (isBun) { const version = await checkPMVersion("bun"); result = { packageManager: "bun", source: "lockfile", ...version && { version } }; } else if (isPnpm) { const version = await checkPMVersion("pnpm"); result = { packageManager: "pnpm", source: "lockfile", ...version && { version } }; } else if (isYarn) { const version = await checkPMVersion("yarn"); result = { packageManager: "yarn", source: "lockfile", ...version && { version } }; } else if (isNpm) { const version = await checkPMVersion("npm"); result = { packageManager: "npm", source: "lockfile", ...version && { version } }; } cache.set(cacheKey, result); return result; } async function detectPackageManagers(projectPath, options = {}) { const cacheKey = `detect_${projectPath}_${options.includeGlobalBun}`; if (cache.has(cacheKey)) { return cache.get(cacheKey); } const detected = []; const lockFileResult = await detectLockFile(projectPath); if (lockFileResult) { detected.push(lockFileResult); } try { const { stdout } = await execa("bun", ["--version"]); if (stdout) { detected.push({ packageManager: "bun", source: "runtime", version: stdout.trim() }); } } catch { } const pkgManagerUserAgent = process.env.npm_config_user_agent ?? ""; if (pkgManagerUserAgent.startsWith("yarn")) { detected.push({ packageManager: "yarn", source: "env" }); } else if (pkgManagerUserAgent.startsWith("pnpm")) { detected.push({ packageManager: "pnpm", source: "env" }); } else if (pkgManagerUserAgent.startsWith("bun")) { detected.push({ packageManager: "bun", source: "env" }); } const configFiles = await Promise.all([ pathExists(path.join(projectPath, ".npmrc")), pathExists(path.join(projectPath, ".yarnrc")), pathExists(path.join(projectPath, ".yarnrc.yml")), pathExists(path.join(projectPath, ".pnpmfile.cjs")), pathExists(path.join(projectPath, ".pnpmfile.js")), pathExists(path.join(projectPath, "bunfig.toml")) ]); const [ hasNpmrc, hasYarnrc, hasYarnrcYml, hasPnpmfileCjs, hasPnpmfileJs, hasBunConfig ] = configFiles; if (hasNpmrc) detected.push({ packageManager: "npm", source: "config" }); if (hasYarnrc || hasYarnrcYml) detected.push({ packageManager: "yarn", source: "config" }); if (hasPnpmfileCjs || hasPnpmfileJs) detected.push({ packageManager: "pnpm", source: "config" }); if (hasBunConfig) detected.push({ packageManager: "bun", source: "config" }); const versionChecks = await Promise.all([ checkPMVersion("npm"), checkPMVersion("pnpm"), checkPMVersion("yarn"), checkPMVersion("bun", options.includeGlobalBun) ]); const pmList = ["npm", "pnpm", "yarn", "bun"]; pmList.forEach((pm, index) => { const version = versionChecks[index]; if (version) { detected.push({ packageManager: pm, source: "global", version }); } }); cache.set(cacheKey, detected); return detected; } export async function getUserPkgManager(projectPath, options = {}) { const defaultPM = { packageManager: "npm", source: "default" }; const priorityOrder = ["bun", "pnpm", "yarn", "npm"]; if (projectPath) { try { const detected = await detectPackageManagers(projectPath, options); if (detected.length === 0) return defaultPM; return priorityOrder.reduce((selected, pm) => { if (selected) return selected; return detected.find((d) => d.packageManager === pm) ?? null; }, null) ?? detected[0] ?? defaultPM; } catch (error) { console.error("Error detecting package manager:", error); return defaultPM; } } let currentDir = process.cwd(); const { root } = path.parse(currentDir); while (currentDir !== root) { const detected = await detectPackageManagers(currentDir, options); if (detected.length > 0) { return priorityOrder.reduce((selected, pm) => { if (selected) return selected; return detected.find((d) => d.packageManager === pm) ?? null; }, null) ?? detected[0] ?? defaultPM; } currentDir = path.dirname(currentDir); } return defaultPM; } export async function getAllPkgManagers(projectPath, options = {}) { try { const detected = await detectPackageManagers(projectPath, options); return detected.length > 0 ? detected : [{ packageManager: "npm", source: "default" }]; } catch (error) { console.error("Error detecting package managers:", error); return [{ packageManager: "npm", source: "default" }]; } }