@@ -22,10 +22,6 @@ class SBOM extends BaseCommand {
22
22
'workspaces' ,
23
23
]
24
24
25
- get #parsedResponse ( ) {
26
- return JSON . stringify ( this . #response, null , 2 )
27
- }
28
-
29
25
async exec ( ) {
30
26
const sbomFormat = this . npm . config . get ( 'sbom-format' )
31
27
const packageLockOnly = this . npm . config . get ( 'package-lock-only' )
@@ -35,56 +31,43 @@ class SBOM extends BaseCommand {
35
31
throw this . usageError ( `Must specify --sbom-format flag with one of: ${ SBOM_FORMATS . join ( ', ' ) } .` )
36
32
}
37
33
38
- const Arborist = require ( '@npmcli/arborist' )
39
-
40
34
const opts = {
41
35
...this . npm . flatOptions ,
42
36
path : this . npm . prefix ,
43
37
forceActual : true ,
44
38
}
39
+ const Arborist = require ( '@npmcli/arborist' )
45
40
const arb = new Arborist ( opts )
46
41
47
- let tree
48
- if ( packageLockOnly ) {
49
- try {
50
- tree = await arb . loadVirtual ( opts )
51
- } catch ( err ) {
52
- /* eslint-disable-next-line max-len */
53
- throw this . usageError ( 'A package lock or shrinkwrap file is required in package-lock-only mode' )
54
- }
55
- } else {
56
- tree = await arb . loadActual ( opts )
57
- }
42
+ const tree = packageLockOnly ? await arb . loadVirtual ( opts ) . catch ( ( ) => {
43
+ /* eslint-disable-next-line max-len */
44
+ throw this . usageError ( 'A package lock or shrinkwrap file is required in package-lock-only mode' )
45
+ } ) : await arb . loadActual ( opts )
58
46
59
47
// Collect the list of selected workspaces in the project
60
- let wsNodes
61
- if ( this . workspaceNames && this . workspaceNames . length ) {
62
- wsNodes = arb . workspaceNodes ( tree , this . workspaceNames )
63
- }
48
+ const wsNodes = this . workspaceNames ?. length
49
+ ? arb . workspaceNodes ( tree , this . workspaceNames )
50
+ : null
64
51
65
52
// Build the selector and query the tree for the list of nodes
66
53
const selector = this . #buildSelector( { wsNodes } )
67
54
log . info ( 'sbom' , `Using dependency selector: ${ selector } ` )
68
55
const items = await tree . querySelectorAll ( selector )
69
56
70
- const errors = new Set ( )
71
- for ( const node of items ) {
72
- detectErrors ( node ) . forEach ( error => errors . add ( error ) )
73
- }
74
-
75
- if ( errors . size > 0 ) {
76
- throw Object . assign (
77
- new Error ( [ ...errors ] . join ( '\n' ) ) ,
78
- { code : 'ESBOMPROBLEMS' }
79
- )
57
+ const errors = items . flatMap ( node => detectErrors ( node ) )
58
+ if ( errors . length ) {
59
+ throw Object . assign ( new Error ( [ ...new Set ( errors ) ] . join ( '\n' ) ) , {
60
+ code : 'ESBOMPROBLEMS' ,
61
+ } )
80
62
}
81
63
82
64
// Populate the response with the list of unique nodes (sorted by location)
83
- this . #buildResponse(
84
- items
85
- . sort ( ( a , b ) => localeCompare ( a . location , b . location ) )
86
- )
87
- output . standard ( this . #parsedResponse)
65
+ this . #buildResponse( items . sort ( ( a , b ) => localeCompare ( a . location , b . location ) ) )
66
+
67
+ // TODO(BREAKING_CHANGE): all sbom output is in json mode but setting it before
68
+ // any of the errors will cause those to be thrown in json mode.
69
+ this . npm . config . set ( 'json' , true )
70
+ output . buffer ( this . #response)
88
71
}
89
72
90
73
async execWorkspaces ( args ) {
@@ -122,10 +105,9 @@ class SBOM extends BaseCommand {
122
105
const packageType = this . npm . config . get ( 'sbom-type' )
123
106
const packageLockOnly = this . npm . config . get ( 'package-lock-only' )
124
107
125
- this . #response =
126
- sbomFormat === 'cyclonedx'
127
- ? cyclonedxOutput ( { npm : this . npm , nodes : items , packageType, packageLockOnly } )
128
- : spdxOutput ( { npm : this . npm , nodes : items , packageType } )
108
+ this . #response = sbomFormat === 'cyclonedx'
109
+ ? cyclonedxOutput ( { npm : this . npm , nodes : items , packageType, packageLockOnly } )
110
+ : spdxOutput ( { npm : this . npm , nodes : items , packageType } )
129
111
}
130
112
}
131
113
0 commit comments