18d3f3824SCedric van Puttenimport fs from 'fs'; 28d3f3824SCedric van Puttenimport path from 'path'; 38d3f3824SCedric van Putten 48d3f3824SCedric van Puttenimport { 58d3f3824SCedric van Putten findPnpmWorkspaceRoot, 68d3f3824SCedric van Putten findYarnOrNpmWorkspaceRoot, 78d3f3824SCedric van Putten NPM_LOCK_FILE, 88d3f3824SCedric van Putten PNPM_LOCK_FILE, 98d3f3824SCedric van Putten YARN_LOCK_FILE, 106a725f6fSColin McDonnell BUN_LOCK_FILE, 118d3f3824SCedric van Putten} from './nodeWorkspaces'; 128a424bebSJames Ideimport { PackageManagerOptions } from '../PackageManager'; 136a725f6fSColin McDonnellimport { BunPackageManager } from '../node/BunPackageManager'; 148a424bebSJames Ideimport { NpmPackageManager } from '../node/NpmPackageManager'; 158a424bebSJames Ideimport { PnpmPackageManager } from '../node/PnpmPackageManager'; 168a424bebSJames Ideimport { YarnPackageManager } from '../node/YarnPackageManager'; 178d3f3824SCedric van Putten 186a725f6fSColin McDonnellexport type NodePackageManager = 196a725f6fSColin McDonnell | NpmPackageManager 206a725f6fSColin McDonnell | PnpmPackageManager 216a725f6fSColin McDonnell | YarnPackageManager 226a725f6fSColin McDonnell | BunPackageManager; 238d3f3824SCedric van Putten 248d3f3824SCedric van Puttenexport type NodePackageManagerForProject = PackageManagerOptions & 258d3f3824SCedric van Putten Partial<Record<NodePackageManager['name'], boolean>>; 268d3f3824SCedric van Putten 278d3f3824SCedric van Putten/** The order of the package managers to use when resolving automatically */ 28*82c7d456SCedric van Puttenexport const RESOLUTION_ORDER: NodePackageManager['name'][] = ['bun', 'yarn', 'npm', 'pnpm']; 298d3f3824SCedric van Putten 308d3f3824SCedric van Putten/** 318d3f3824SCedric van Putten * Resolve the workspace root for a project, if its part of a monorepo. 328d3f3824SCedric van Putten * Optionally, provide a specific packager to only resolve that one specifically. 338d3f3824SCedric van Putten */ 348d3f3824SCedric van Puttenexport function findWorkspaceRoot( 358d3f3824SCedric van Putten projectRoot: string, 368d3f3824SCedric van Putten preferredManager?: NodePackageManager['name'] 378d3f3824SCedric van Putten): string | null { 388d3f3824SCedric van Putten const strategies: Record<NodePackageManager['name'], (projectRoot: string) => string | null> = { 398d3f3824SCedric van Putten npm: findYarnOrNpmWorkspaceRoot, 408d3f3824SCedric van Putten yarn: findYarnOrNpmWorkspaceRoot, 418d3f3824SCedric van Putten pnpm: findPnpmWorkspaceRoot, 426a725f6fSColin McDonnell bun: findYarnOrNpmWorkspaceRoot, 438d3f3824SCedric van Putten }; 448d3f3824SCedric van Putten 458d3f3824SCedric van Putten if (preferredManager) { 468d3f3824SCedric van Putten return strategies[preferredManager](projectRoot); 478d3f3824SCedric van Putten } 488d3f3824SCedric van Putten 498d3f3824SCedric van Putten for (const strategy of RESOLUTION_ORDER) { 508d3f3824SCedric van Putten const root = strategies[strategy](projectRoot); 518d3f3824SCedric van Putten if (root) { 528d3f3824SCedric van Putten return root; 538d3f3824SCedric van Putten } 548d3f3824SCedric van Putten } 558d3f3824SCedric van Putten 568d3f3824SCedric van Putten return null; 578d3f3824SCedric van Putten} 588d3f3824SCedric van Putten 598d3f3824SCedric van Putten/** 608d3f3824SCedric van Putten * Resolve the used node package manager for a project by checking the lockfile. 618d3f3824SCedric van Putten * This also tries to resolve the workspace root, if its part of a monorepo. 628d3f3824SCedric van Putten * Optionally, provide a preferred packager to only resolve that one specifically. 638d3f3824SCedric van Putten */ 648d3f3824SCedric van Puttenexport function resolvePackageManager( 658d3f3824SCedric van Putten projectRoot: string, 668d3f3824SCedric van Putten preferredManager?: NodePackageManager['name'] 678d3f3824SCedric van Putten): NodePackageManager['name'] | null { 688d3f3824SCedric van Putten const root = findWorkspaceRoot(projectRoot, preferredManager) ?? projectRoot; 698d3f3824SCedric van Putten const lockFiles: Record<NodePackageManager['name'], string> = { 708d3f3824SCedric van Putten npm: NPM_LOCK_FILE, 718d3f3824SCedric van Putten pnpm: PNPM_LOCK_FILE, 728d3f3824SCedric van Putten yarn: YARN_LOCK_FILE, 736a725f6fSColin McDonnell bun: BUN_LOCK_FILE, 748d3f3824SCedric van Putten }; 758d3f3824SCedric van Putten 768d3f3824SCedric van Putten if (preferredManager) { 778d3f3824SCedric van Putten if (fs.existsSync(path.join(root, lockFiles[preferredManager]))) { 788d3f3824SCedric van Putten return preferredManager; 798d3f3824SCedric van Putten } 808d3f3824SCedric van Putten 818d3f3824SCedric van Putten return null; 828d3f3824SCedric van Putten } 838d3f3824SCedric van Putten 848d3f3824SCedric van Putten for (const managerName of RESOLUTION_ORDER) { 858d3f3824SCedric van Putten if (fs.existsSync(path.join(root, lockFiles[managerName]))) { 868d3f3824SCedric van Putten return managerName; 878d3f3824SCedric van Putten } 888d3f3824SCedric van Putten } 898d3f3824SCedric van Putten 908d3f3824SCedric van Putten return null; 918d3f3824SCedric van Putten} 928d3f3824SCedric van Putten 938d3f3824SCedric van Putten/** 948d3f3824SCedric van Putten * This creates a Node package manager from the provided options. 958d3f3824SCedric van Putten * If these options are not provided, it will infer the package manager from lockfiles. 968d3f3824SCedric van Putten * When no package manager is found, it falls back to npm. 978d3f3824SCedric van Putten */ 988d3f3824SCedric van Puttenexport function createForProject( 998d3f3824SCedric van Putten projectRoot: string, 1008d3f3824SCedric van Putten options: NodePackageManagerForProject = {} 1018d3f3824SCedric van Putten): NodePackageManager { 1028d3f3824SCedric van Putten if (options.npm) { 1038d3f3824SCedric van Putten return new NpmPackageManager({ cwd: projectRoot, ...options }); 1048d3f3824SCedric van Putten } else if (options.yarn) { 1058d3f3824SCedric van Putten return new YarnPackageManager({ cwd: projectRoot, ...options }); 1068d3f3824SCedric van Putten } else if (options.pnpm) { 1078d3f3824SCedric van Putten return new PnpmPackageManager({ cwd: projectRoot, ...options }); 1086a725f6fSColin McDonnell } else if (options.bun) { 1096a725f6fSColin McDonnell return new BunPackageManager({ cwd: projectRoot, ...options }); 1108d3f3824SCedric van Putten } 1118d3f3824SCedric van Putten 1128d3f3824SCedric van Putten switch (resolvePackageManager(projectRoot)) { 1138d3f3824SCedric van Putten case 'npm': 1148d3f3824SCedric van Putten return new NpmPackageManager({ cwd: projectRoot, ...options }); 1158d3f3824SCedric van Putten case 'pnpm': 1168d3f3824SCedric van Putten return new PnpmPackageManager({ cwd: projectRoot, ...options }); 1178d3f3824SCedric van Putten case 'yarn': 1188d3f3824SCedric van Putten return new YarnPackageManager({ cwd: projectRoot, ...options }); 1196a725f6fSColin McDonnell case 'bun': 1206a725f6fSColin McDonnell return new BunPackageManager({ cwd: projectRoot, ...options }); 1218d3f3824SCedric van Putten default: 1228d3f3824SCedric van Putten return new NpmPackageManager({ cwd: projectRoot, ...options }); 1238d3f3824SCedric van Putten } 1248d3f3824SCedric van Putten} 125