UNPKG

@lenne.tech/cli

Version:

lenne.Tech CLI: lt

249 lines (248 loc) 7.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PackageManager = void 0; const path_1 = require("path"); const LOCKFILE_MAP = { 'package-lock.json': 'npm', 'pnpm-lock.yaml': 'pnpm', 'yarn.lock': 'yarn', }; /** * Package manager detection and command builder * Automatically detects npm, pnpm, or yarn based on lockfiles and config */ class PackageManager { constructor(filesystem, ltConfigFn) { this.cache = new Map(); this.filesystem = filesystem; this.ltConfig = ltConfigFn; } /** * Add a package to the project * @param pkg - Package name (with optional version) * @param flags - Additional flags (e.g., '--save-dev', '--save-exact') * @param pm - Override detected package manager */ addPackage(pkg, flags, pm) { const manager = pm || this.detect(); const flagStr = flags ? ` ${flags}` : ''; switch (manager) { case 'pnpm': return `pnpm add ${pkg}${flagStr}`; case 'yarn': return `yarn add ${pkg}${flagStr}`; default: return `npm install ${pkg}${flagStr}`; } } /** * Get the binary/executable runner command * @param pm - Override detected package manager */ bin(pm) { const manager = pm || this.detect(); return manager; } /** * Get the cache clean command * @param pm - Override detected package manager */ cacheClean(pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return 'pnpm store prune'; case 'yarn': return 'yarn cache clean'; default: return 'npm cache clean --force'; } } /** * Detect the package manager for the given directory * Uses caching per directory for performance * * Priority: * 1. Lockfile in cwd * 2. packageManager field in package.json * 3. Lockfile in parent directories (monorepo support) * 4. Config fallback (defaults.packageManager) * 5. npm * * @param cwd - Directory to detect from (defaults to filesystem.cwd()) */ detect(cwd) { const dir = cwd || this.filesystem.cwd(); if (this.cache.has(dir)) { return this.cache.get(dir); } const result = this.detectFromLockfile(dir) || this.detectFromPackageJson(dir) || this.detectFromParentDirs(dir) || this.detectFromConfig() || 'npm'; this.cache.set(dir, result); return result; } /** * Get the npx/dlx equivalent command * @param cmd - Command to execute * @param pm - Override detected package manager */ exec(cmd, pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return `pnpm dlx ${cmd}`; case 'yarn': return `yarn dlx ${cmd}`; default: return `npx ${cmd}`; } } /** * Get the lockfile name for the given package manager * @param pm - Override detected package manager */ getLockfileName(pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return 'pnpm-lock.yaml'; case 'yarn': return 'yarn.lock'; default: return 'package-lock.json'; } } /** * Get the global install command * @param pkg - Package name * @param pm - Override detected package manager */ globalInstall(pkg, pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return `pnpm add -g ${pkg}`; case 'yarn': return `yarn global add ${pkg}`; default: return `npm i -g ${pkg}`; } } /** * Get the install command (no arguments) * @param pm - Override detected package manager */ install(pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return 'pnpm install'; case 'yarn': return 'yarn install'; default: return 'npm i'; } } /** * Get the run script command * @param script - Script name from package.json * @param pm - Override detected package manager */ run(script, pm) { const manager = pm || this.detect(); switch (manager) { case 'pnpm': return `pnpm run ${script}`; case 'yarn': return `yarn run ${script}`; default: return `npm run ${script}`; } } /** * Detect from lt.config defaults.packageManager */ detectFromConfig() { var _a; try { const config = this.ltConfig(); const pm = (_a = config === null || config === void 0 ? void 0 : config.defaults) === null || _a === void 0 ? void 0 : _a.packageManager; if (pm && ['npm', 'pnpm', 'yarn'].includes(pm)) { return pm; } } catch (_b) { // Config not available } return null; } /** * Detect package manager from lockfile in the given directory */ detectFromLockfile(dir) { for (const [lockfile, pm] of Object.entries(LOCKFILE_MAP)) { if (this.filesystem.exists((0, path_1.join)(dir, lockfile))) { return pm; } } return null; } /** * Detect from packageManager field in package.json (Corepack standard) */ detectFromPackageJson(dir) { const pkgPath = (0, path_1.join)(dir, 'package.json'); if (!this.filesystem.exists(pkgPath)) { return null; } try { const content = this.filesystem.read(pkgPath, 'json'); const pmField = content === null || content === void 0 ? void 0 : content.packageManager; if (typeof pmField === 'string') { if (pmField.startsWith('pnpm')) { return 'pnpm'; } if (pmField.startsWith('yarn')) { return 'yarn'; } if (pmField.startsWith('npm')) { return 'npm'; } } } catch (_a) { // Invalid package.json } return null; } /** * Detect from lockfile in parent directories (monorepo support) */ detectFromParentDirs(startDir) { let dir = startDir; const root = this.filesystem.separator === '/' ? '/' : /^[A-Z]:\\$/i; while (true) { const parent = this.filesystem.path(dir, '..'); if (parent === dir || (typeof root !== 'string' && root.test(dir))) { break; } dir = parent; const result = this.detectFromLockfile(dir); if (result) { return result; } } return null; } } exports.PackageManager = PackageManager; /** * Extension function to add package manager helper to toolbox */ exports.default = (toolbox) => { const pm = new PackageManager(toolbox.filesystem, () => { var _a, _b; return ((_b = (_a = toolbox.config) === null || _a === void 0 ? void 0 : _a.loadConfig) === null || _b === void 0 ? void 0 : _b.call(_a)) || {}; }); toolbox.pm = pm; };