1
- import { execSync } from "node:child_process"
2
1
import fs from 'node:fs'
3
2
import os from "node:os" ;
4
- import { getCustomPath , handleSpacesInPath } from "../tools.js" ;
3
+ import { getCustomPath , invokeCommand } from "../tools.js" ;
5
4
import path from 'node:path'
6
5
import Sbom from '../sbom.js'
7
6
import { PackageURL } from 'packageurl-js'
8
7
9
- export var npmInteractions = {
10
- listing : function runNpmListing ( npmListing ) {
11
- let npmOutput = execSync ( npmListing , err => {
12
- if ( err ) {
13
- throw new Error ( 'failed to get npmOutput json from npm' )
14
- }
15
- } ) ;
16
- return npmOutput ;
8
+ var npmInteractions = {
9
+ listing : function runNpmListing ( npm , manifestDir , includeAll ) {
10
+ return invokeCommand ( npm , [ 'ls' , includeAll ? '--all' : '' , '--omit=dev' , '--package-lock-only' , '--json' , '--prefix' , manifestDir ] , error => {
11
+ throw new Error ( 'failed to get npmOutput json from npm' , { cause : error } )
12
+ } ) . toString ( )
17
13
} ,
18
14
version : function checkNpmVersion ( npm ) {
19
- execSync ( ` ${ handleSpacesInPath ( npm ) } --version` , err => {
20
- if ( err ) {
21
- throw new Error ( ' npm is not accessible' )
15
+ invokeCommand ( npm , [ ' --version' ] , error => {
16
+ if ( error . code === 'ENOENT' ) {
17
+ throw new Error ( ` npm is not accessible at ${ npm } ` , { } )
22
18
}
19
+ throw new Error ( 'failed to check for npm' , { cause : error } )
23
20
} )
24
21
} ,
25
22
createPackageLock : function createPackageLock ( npm , manifestDir ) {
26
- // in windows os, --prefix flag doesn't work, it behaves really weird , instead of installing the package.json fromm the prefix folder,
27
- // it's installing package.json (placed in current working directory of process) into prefix directory, so
23
+ // in windows os, --prefix flag doesn't work, it behaves really weird , instead of installing the package.json fromm the prefix folder,
24
+ // it's installing package.json (placed in current working directory of process) into prefix directory, so
28
25
let originalDir = process . cwd ( )
29
26
if ( os . platform ( ) === 'win32' ) {
30
27
process . chdir ( manifestDir )
31
28
}
32
- execSync ( `${ handleSpacesInPath ( npm ) } i --package-lock-only --prefix ${ handleSpacesInPath ( manifestDir ) } ` , err => {
33
- if ( err ) {
34
- throw new Error ( 'failed to create npmOutput list' )
35
- }
29
+ invokeCommand ( npm , [ 'i' , '--package-lock-only' , '--prefix' , manifestDir ] , error => {
30
+ throw new Error ( 'failed to create npmOutput list' , { cause : error } )
36
31
} )
37
32
if ( os . platform ( ) === 'win32' ) {
38
33
process . chdir ( originalDir )
39
34
}
40
35
}
41
36
}
42
- export default { isSupported, validateLockFile, provideComponent, provideStack, npmInteractions }
37
+ export default { isSupported, validateLockFile, provideComponent, provideStack }
43
38
44
39
/** @typedef {import('../provider').Provider } */
45
40
@@ -100,22 +95,11 @@ function provideStack(manifest, opts = {}) {
100
95
function provideComponent ( manifest , opts = { } ) {
101
96
return {
102
97
ecosystem,
103
- content : getSBOM ( manifest , opts , false ) ,
98
+ content : getSBOM ( manifest , opts , false ) ,
104
99
contentType : 'application/vnd.cyclonedx+json'
105
100
}
106
101
}
107
102
108
- /**
109
- *
110
- * @param {string } npm the npm binary path
111
- * @param {string }allFilter can be "-all" ( for stack analysis) or empty string ( for component analysis).
112
- * @param {string } manifestDir path to manifest' directory.
113
- * @return {string } returns a string containing the result output.
114
- */
115
- function getNpmListing ( npm , allFilter , manifestDir ) {
116
- return `${ handleSpacesInPath ( npm ) } ls${ allFilter } --omit=dev --package-lock-only --json --prefix ${ manifestDir } ` ;
117
- }
118
-
119
103
/**
120
104
* Create SBOM json string for npm Package.
121
105
* @param {string } manifest - path for package.json
@@ -130,9 +114,7 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
130
114
npmInteractions . version ( npm ) ;
131
115
let manifestDir = path . dirname ( manifest )
132
116
npmInteractions . createPackageLock ( npm , manifestDir ) ;
133
- let allFilter = includeTransitive ? " --all" : ""
134
- let npmListing = getNpmListing ( npm , allFilter , handleSpacesInPath ( manifestDir ) )
135
- let npmOutput = npmInteractions . listing ( npmListing ) ;
117
+ let npmOutput = npmInteractions . listing ( npm , manifestDir , includeTransitive ) ;
136
118
let depsObject = JSON . parse ( npmOutput ) ;
137
119
let rootName = depsObject [ "name" ]
138
120
let rootVersion = depsObject [ "version" ]
@@ -165,16 +147,11 @@ function getSBOM(manifest, opts = {}, includeTransitive) {
165
147
*/
166
148
function toPurl ( name , version ) {
167
149
let parts = name . split ( "/" ) ;
168
- var pkg
169
- if ( parts . length === 2 )
170
- {
171
- pkg = new PackageURL ( 'npm' , parts [ 0 ] , parts [ 1 ] , version , undefined , undefined ) ;
172
- }
173
- else
174
- {
175
- pkg = new PackageURL ( 'npm' , undefined , parts [ 0 ] , version , undefined , undefined ) ;
150
+ if ( parts . length === 2 ) {
151
+ return new PackageURL ( 'npm' , parts [ 0 ] , parts [ 1 ] , version , undefined , undefined ) ;
152
+ } else {
153
+ return new PackageURL ( 'npm' , undefined , parts [ 0 ] , version , undefined , undefined ) ;
176
154
}
177
- return pkg
178
155
}
179
156
180
157
/**
@@ -188,13 +165,11 @@ function addAllDependencies(sbom, from, dependencies) {
188
165
Object . entries ( dependencies )
189
166
. filter ( entry => entry [ 1 ] . version !== undefined )
190
167
. forEach ( entry => {
191
- let name , artifact ;
192
- [ name , artifact ] = entry ;
168
+ let [ name , artifact ] = entry ;
193
169
let purl = toPurl ( name , artifact . version ) ;
194
170
sbom . addDependency ( from , purl )
195
171
let transitiveDeps = artifact . dependencies
196
- if ( transitiveDeps !== undefined )
197
- {
172
+ if ( transitiveDeps !== undefined ) {
198
173
addAllDependencies ( sbom , sbom . purlToComponent ( purl ) , transitiveDeps )
199
174
}
200
175
} ) ;
0 commit comments