@@ -7,8 +7,9 @@ import ora from 'ora'
7
7
import { handleApiCall , handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
8
8
import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
9
9
import { InputError } from '../../utils/errors.js'
10
- import { getSeveritySummary } from '../../utils/format-issues.js'
10
+ import { getSeverityCount , formatSeverityCount } from '../../utils/format-issues.js'
11
11
import { printFlagList } from '../../utils/formatting.js'
12
+ import { objectSome } from '../../utils/misc.js'
12
13
import { setupSdk } from '../../utils/sdk.js'
13
14
14
15
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand } */
@@ -18,32 +19,44 @@ export const info = {
18
19
const name = parentName + ' info'
19
20
20
21
const input = setupCommand ( name , info . description , argv , importMeta )
21
- const result = input && await fetchPackageData ( input . pkgName , input . pkgVersion )
22
+ const packageData = input && await fetchPackageData ( input . pkgName , input . pkgVersion , input )
22
23
23
- if ( result ) {
24
- formatPackageDataOutput ( result . data , { name, ...input } )
24
+ if ( packageData ) {
25
+ formatPackageDataOutput ( packageData , { name, ...input } )
25
26
}
26
27
}
27
28
}
28
29
29
30
// Internal functions
30
31
32
+ /**
33
+ * @typedef CommandContext
34
+ * @property {boolean } includeAllIssues
35
+ * @property {boolean } outputJson
36
+ * @property {boolean } outputMarkdown
37
+ * @property {string } pkgName
38
+ * @property {string } pkgVersion
39
+ * @property {boolean } strict
40
+ */
41
+
31
42
/**
32
43
* @param {string } name
33
44
* @param {string } description
34
45
* @param {readonly string[] } argv
35
46
* @param {ImportMeta } importMeta
36
- * @returns {void|{ outputJson: boolean, outputMarkdown: boolean, pkgName: string, pkgVersion: string } }
47
+ * @returns {void|CommandContext }
37
48
*/
38
- function setupCommand ( name , description , argv , importMeta ) {
49
+ function setupCommand ( name , description , argv , importMeta ) {
39
50
const cli = meow ( `
40
51
Usage
41
52
$ ${ name } <name>
42
53
43
54
Options
44
55
${ printFlagList ( {
56
+ '--all' : 'Include all issues' ,
45
57
'--json' : 'Output result as json' ,
46
58
'--markdown' : 'Output result as markdown' ,
59
+ '--strict' : 'Exits with an error code if any matching issues are found' ,
47
60
} , 6 ) }
48
61
49
62
Examples
@@ -54,6 +67,10 @@ export const info = {
54
67
description,
55
68
importMeta,
56
69
flags : {
70
+ all : {
71
+ type : 'boolean' ,
72
+ default : false ,
73
+ } ,
57
74
json : {
58
75
type : 'boolean' ,
59
76
alias : 'j' ,
@@ -64,12 +81,18 @@ export const info = {
64
81
alias : 'm' ,
65
82
default : false ,
66
83
} ,
84
+ strict : {
85
+ type : 'boolean' ,
86
+ default : false ,
87
+ } ,
67
88
}
68
89
} )
69
90
70
91
const {
92
+ all : includeAllIssues ,
71
93
json : outputJson ,
72
94
markdown : outputMarkdown ,
95
+ strict,
73
96
} = cli . flags
74
97
75
98
if ( cli . input . length > 1 ) {
@@ -97,19 +120,28 @@ export const info = {
97
120
}
98
121
99
122
return {
123
+ includeAllIssues,
100
124
outputJson,
101
125
outputMarkdown,
102
126
pkgName,
103
- pkgVersion
127
+ pkgVersion,
128
+ strict,
104
129
}
105
130
}
106
131
132
+ /**
133
+ * @typedef PackageData
134
+ * @property {import('@socketsecurity/sdk').SocketSdkReturnType<'getIssuesByNPMPackage'>["data"] } data
135
+ * @property {Record<import('../../utils/format-issues').SocketIssue['severity'], number> } severityCount
136
+ */
137
+
107
138
/**
108
139
* @param {string } pkgName
109
140
* @param {string } pkgVersion
110
- * @returns {Promise<void|import('@socketsecurity/sdk').SocketSdkReturnType<'getIssuesByNPMPackage'>> }
141
+ * @param {Pick<CommandContext, 'includeAllIssues' | 'strict'> } context
142
+ * @returns {Promise<void|PackageData> }
111
143
*/
112
- async function fetchPackageData ( pkgName , pkgVersion ) {
144
+ async function fetchPackageData ( pkgName , pkgVersion , { includeAllIssues , strict } ) {
113
145
const socketSdk = await setupSdk ( )
114
146
const spinner = ora ( `Looking up data for version ${ pkgVersion } of ${ pkgName } ` ) . start ( )
115
147
const result = await handleApiCall ( socketSdk . getIssuesByNPMPackage ( pkgName , pkgVersion ) , spinner , 'looking up package' )
@@ -120,32 +152,40 @@ async function fetchPackageData (pkgName, pkgVersion) {
120
152
121
153
// Conclude the status of the API call
122
154
123
- const issueSummary = getSeveritySummary ( result . data )
124
- spinner . succeed ( `Found ${ issueSummary || 'no' } issues for version ${ pkgVersion } of ${ pkgName } ` )
155
+ const severityCount = getSeverityCount ( result . data , includeAllIssues ? undefined : 'high' )
156
+
157
+ if ( objectSome ( severityCount ) ) {
158
+ const issueSummary = formatSeverityCount ( severityCount )
159
+ spinner [ strict ? 'fail' : 'succeed' ] ( `Package has these issues: ${ issueSummary } ` )
160
+ } else {
161
+ spinner . succeed ( 'Package has no issues' )
162
+ }
125
163
126
- return result
164
+ return {
165
+ data : result . data ,
166
+ severityCount,
167
+ }
127
168
}
128
169
129
170
/**
130
- * @param {import('@socketsecurity/sdk').SocketSdkReturnType<'getIssuesByNPMPackage'>["data"] } data
131
- * @param {{ name: string, outputJson: boolean, outputMarkdown: boolean, pkgName: string, pkgVersion: string } } context
171
+ * @param {PackageData } packageData
172
+ * @param {{ name: string } & CommandContext } context
132
173
* @returns {void }
133
174
*/
134
- function formatPackageDataOutput ( data , { name, outputJson, outputMarkdown, pkgName, pkgVersion } ) {
135
- // If JSON, output and return...
136
-
175
+ function formatPackageDataOutput ( { data, severityCount } , { name, outputJson, outputMarkdown, pkgName, pkgVersion, strict } ) {
137
176
if ( outputJson ) {
138
177
console . log ( JSON . stringify ( data , undefined , 2 ) )
139
- return
140
- }
141
-
142
- // ...else do the CLI / Markdown output dance
178
+ } else {
179
+ const format = new ChalkOrMarkdown ( ! ! outputMarkdown )
180
+ const url = `https://socket.dev/npm/package/${ pkgName } /overview/${ pkgVersion } `
143
181
144
- const format = new ChalkOrMarkdown ( ! ! outputMarkdown )
145
- const url = `https://socket.dev/npm/package/${ pkgName } /overview/${ pkgVersion } `
182
+ console . log ( '\nDetailed info on socket.dev: ' + format . hyperlink ( `${ pkgName } v${ pkgVersion } ` , url , { fallbackToUrl : true } ) )
183
+ if ( ! outputMarkdown ) {
184
+ console . log ( chalk . dim ( '\nOr rerun' , chalk . italic ( name ) , 'using the' , chalk . italic ( '--json' ) , 'flag to get full JSON output' ) )
185
+ }
186
+ }
146
187
147
- console . log ( '\nDetailed info on socket.dev: ' + format . hyperlink ( `${ pkgName } v${ pkgVersion } ` , url , { fallbackToUrl : true } ) )
148
- if ( ! outputMarkdown ) {
149
- console . log ( chalk . dim ( '\nOr rerun' , chalk . italic ( name ) , 'using the' , chalk . italic ( '--json' ) , 'flag to get full JSON output' ) )
188
+ if ( strict && objectSome ( severityCount ) ) {
189
+ process . exit ( 1 )
150
190
}
151
191
}
0 commit comments