import spawn from "cross-spawn" ; import path from "path" ; import fs from "fs" ; type UpdateOpts = { type : "dependencies" | "devDependencies" ; cwd : string ; pkgs : string [ ] ; verbose : boolean ; } ; function Implementation < T extends string > ( impl ) { return impl ; } const NPM = Implementation ( { type : "npm" , add ( opts ) { return spawn . sync ( "npm" , [ "install" , "--save-exact" , ... opts . pkgs , opts . type === "dependencies" ? "--save" : "--save-dev" , ] , { cwd : opts . cwd , stdio : opts . verbose ? "inherit" : undefined , } ) ; } , } ) ; const Yarn = Implementation ( { type : "yarn" , add ( opts ) { return spawn . sync ( "yarn" , [ "add" , "--exact" , ( opts . type === "devDependencies" && "--dev" ) || "" , "-W" , ... opts . pkgs , ] . filter ( ( item ) => item ) , { cwd : opts . cwd , stdio : opts . verbose ? "inherit" : undefined , } ) ; } , } ) ; type Manager = typeof NPM | typeof Yarn ; export function getManager ( dir ) { const lock = path . join ( dir , "yarn.lock" ) ; if ( fs . existsSync ( lock ) ) return Yarn ; const upDir = path . resolve ( dir , ".." ) ; if ( upDir === dir ) { return NPM ; } return getManager ( upDir ) ; }