1
- import { promisify } from "node:util" ;
2
- import * as path from "node:path" ;
3
1
import { InstallOptions } from "./commands" ;
4
- import { JsrPackage , findLockFile , findPackageJson , logDebug } from "./utils" ;
5
- import * as cp from "node:child_process" ;
2
+ import { JsrPackage , findProjectDir } from "./utils" ;
3
+ import { spawn } from "node:child_process" ;
4
+ import * as kl from "kolorist" ;
6
5
7
- const execAsync = promisify ( cp . exec ) ;
8
- const exec = ( cmd : string , options : cp . ExecOptions ) => {
9
- logDebug ( `$ ${ cmd } ` ) ;
10
- return execAsync ( cmd , options ) ;
6
+ const exec = async ( cmd : string , args : string [ ] , cwd : string ) => {
7
+ console . log ( kl . dim ( `$ ${ cmd } ${ args . join ( " " ) } ` ) ) ;
8
+
9
+ const cp = spawn ( cmd , args , { stdio : "inherit" } ) ;
10
+
11
+ return new Promise < void > ( ( resolve ) => {
12
+ cp . on ( "exit" , ( code ) => {
13
+ if ( code === 0 ) resolve ( ) ;
14
+ else process . exit ( code ?? 1 ) ;
15
+ } ) ;
16
+ } ) ;
11
17
} ;
12
18
13
19
function modeToFlag ( mode : InstallOptions [ "mode" ] ) : string {
@@ -18,106 +24,102 @@ function modeToFlag(mode: InstallOptions["mode"]): string {
18
24
: "" ;
19
25
}
20
26
21
- function toPackageArgs ( pkgs : JsrPackage [ ] ) : string {
22
- return pkgs
23
- . map ( ( pkg ) => `@${ pkg . scope } /${ pkg . name } @npm:${ pkg . toNpmPackage ( ) } ` )
24
- . join ( " " ) ;
25
- }
26
-
27
- function toMappedArg ( pkgs : JsrPackage [ ] ) : string {
28
- return pkgs . map ( ( pkg ) => pkg . toString ( ) ) . join ( " " ) ;
27
+ function toPackageArgs ( pkgs : JsrPackage [ ] ) : string [ ] {
28
+ return pkgs . map (
29
+ ( pkg ) => `@${ pkg . scope } /${ pkg . name } @npm:${ pkg . toNpmPackage ( ) } `
30
+ ) ;
29
31
}
30
32
31
33
export interface PackageManager {
34
+ cwd : string ;
32
35
install ( packages : JsrPackage [ ] , options : InstallOptions ) : Promise < void > ;
33
36
remove ( packages : JsrPackage [ ] ) : Promise < void > ;
34
37
}
35
38
36
39
class Npm implements PackageManager {
37
- constructor ( private cwd : string ) { }
40
+ constructor ( public cwd : string ) { }
38
41
39
42
async install ( packages : JsrPackage [ ] , options : InstallOptions ) {
43
+ const args = [ "install" ] ;
40
44
const mode = modeToFlag ( options . mode ) ;
41
- await exec ( `npm install ${ mode } ${ toPackageArgs ( packages ) } ` , {
42
- cwd : this . cwd ,
43
- } ) ;
45
+ if ( mode !== "" ) {
46
+ args . push ( mode ) ;
47
+ }
48
+ args . push ( ...toPackageArgs ( packages ) ) ;
49
+
50
+ await exec ( "npm" , args , this . cwd ) ;
44
51
}
45
52
46
53
async remove ( packages : JsrPackage [ ] ) {
47
- await exec ( `npm remove ${ toMappedArg ( packages ) } ` , {
48
- cwd : this . cwd ,
49
- } ) ;
54
+ await exec (
55
+ "npm" ,
56
+ [ "remove" , ...packages . map ( ( pkg ) => pkg . toString ( ) ) ] ,
57
+ this . cwd
58
+ ) ;
50
59
}
51
60
}
52
61
53
62
class Yarn implements PackageManager {
54
- constructor ( private cwd : string ) { }
63
+ constructor ( public cwd : string ) { }
55
64
56
65
async install ( packages : JsrPackage [ ] , options : InstallOptions ) {
66
+ const args = [ "add" ] ;
57
67
const mode = modeToFlag ( options . mode ) ;
58
- await exec ( `yarn add ${ mode } ${ toPackageArgs ( packages ) } ` , {
59
- cwd : this . cwd ,
60
- } ) ;
68
+ if ( mode !== "" ) {
69
+ args . push ( mode ) ;
70
+ }
71
+ args . push ( ...toPackageArgs ( packages ) ) ;
72
+ await exec ( "yarn" , args , this . cwd ) ;
61
73
}
62
74
63
75
async remove ( packages : JsrPackage [ ] ) {
64
- await exec ( `yarn remove ${ toMappedArg ( packages ) } ` , {
65
- cwd : this . cwd ,
66
- } ) ;
76
+ await exec (
77
+ "yarn" ,
78
+ [ "remove" , ...packages . map ( ( pkg ) => pkg . toString ( ) ) ] ,
79
+ this . cwd
80
+ ) ;
67
81
}
68
82
}
69
83
70
84
class Pnpm implements PackageManager {
71
- constructor ( private cwd : string ) { }
85
+ constructor ( public cwd : string ) { }
72
86
73
87
async install ( packages : JsrPackage [ ] , options : InstallOptions ) {
88
+ const args = [ "add" ] ;
74
89
const mode = modeToFlag ( options . mode ) ;
75
- await exec ( `pnpm add ${ mode } ${ toPackageArgs ( packages ) } ` , {
76
- cwd : this . cwd ,
77
- } ) ;
90
+ if ( mode !== "" ) {
91
+ args . push ( mode ) ;
92
+ }
93
+ args . push ( ...toPackageArgs ( packages ) ) ;
94
+ await exec ( "pnpm" , args , this . cwd ) ;
78
95
}
79
96
80
97
async remove ( packages : JsrPackage [ ] ) {
81
- cp . execSync ( `pnpm remove ${ toMappedArg ( packages ) } ` , {
82
- cwd : this . cwd ,
83
- } ) ;
98
+ await exec (
99
+ "yarn" ,
100
+ [ "remove" , ...packages . map ( ( pkg ) => pkg . toString ( ) ) ] ,
101
+ this . cwd
102
+ ) ;
84
103
}
85
104
}
86
105
87
- export async function getProjectDir ( cwd : string ) : Promise < {
88
- projectDir : string ;
89
- lockFilePath : string | null ;
90
- } > {
91
- const lockFilePath = await findLockFile ( cwd ) ;
92
- if ( lockFilePath !== null ) {
93
- const projectDir = path . dirname ( lockFilePath ) ;
94
- return { lockFilePath, projectDir } ;
95
- }
106
+ export type PkgManagerName = "npm" | "yarn" | "pnpm" ;
96
107
97
- const pkgJsonPath = await findPackageJson ( cwd ) ;
98
- if ( pkgJsonPath !== null ) {
99
- const projectDir = path . dirname ( pkgJsonPath ) ;
100
- return { lockFilePath : null , projectDir } ;
101
- }
108
+ export async function getPkgManager (
109
+ cwd : string ,
110
+ pkgManagerName : PkgManagerName | null
111
+ ) {
112
+ const { projectDir, pkgManagerName : foundPkgManager } = await findProjectDir (
113
+ cwd
114
+ ) ;
102
115
103
- return { lockFilePath : null , projectDir : cwd } ;
104
- }
116
+ const result = pkgManagerName || foundPkgManager || "npm" ;
105
117
106
- export function detectPackageManager (
107
- lockFilePath : string | null ,
108
- projectDir : string
109
- ) : PackageManager {
110
- if ( lockFilePath !== null ) {
111
- const filename = path . basename ( lockFilePath ) ;
112
- if ( filename === "package-lock.json" ) {
113
- return new Npm ( projectDir ) ;
114
- } else if ( filename === "yarn.lock" ) {
115
- return new Yarn ( projectDir ) ;
116
- } else if ( filename === "pnpm-lock.yml" ) {
117
- return new Pnpm ( projectDir ) ;
118
- }
118
+ if ( result === "yarn" ) {
119
+ return new Yarn ( projectDir ) ;
120
+ } else if ( result === "pnpm" ) {
121
+ return new Pnpm ( projectDir ) ;
119
122
}
120
123
121
- // Fall back to npm if no lockfile is present.
122
124
return new Npm ( projectDir ) ;
123
125
}
0 commit comments