Skip to content

Commit c0d5caa

Browse files
committed
wip
1 parent 844e3cb commit c0d5caa

File tree

1 file changed

+95
-81
lines changed

1 file changed

+95
-81
lines changed

lib/commands/info/index.js

Lines changed: 95 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ export const info = {
2121

2222
const input = setupCommand(name, info.description, argv, importMeta)
2323
if (input) {
24-
const spinnerText = input.pkgVersion === 'latest' ? `Looking up data for the latest version of ${input.pkgName}\n` : `Looking up data for version ${input.pkgVersion} of ${input.pkgName}\n`
24+
const spinnerText = `Looking up data for packages: ${input.packages.join(', ')}\n`
2525
const spinner = ora(spinnerText).start()
26-
const packageData = await fetchPackageData(input.ecosystem, input.pkgName, input.pkgVersion, input, spinner)
26+
const packageData = await fetchPackageData(input.packages, input.includeAlerts, spinner)
2727
if (packageData) {
2828
formatPackageDataOutput(packageData, { name, ...input }, spinner)
2929
}
@@ -32,12 +32,14 @@ export const info = {
3232
}
3333

3434
const infoFlags = prepareFlags({
35-
license: {
36-
type: 'boolean',
37-
shortFlag: 'l',
38-
default: false,
39-
description: 'Include license - Default is false',
40-
},
35+
// At the moment in API v0, alerts and license do the same thing.
36+
// The license parameter will be implemented later.
37+
// license: {
38+
// type: 'boolean',
39+
// shortFlag: 'l',
40+
// default: false,
41+
// description: 'Include license - Default is false',
42+
// },
4143
alerts: {
4244
type: 'boolean',
4345
shortFlag: 'a',
@@ -53,11 +55,8 @@ const infoFlags = prepareFlags({
5355
* @property {boolean} includeAlerts
5456
* @property {boolean} outputJson
5557
* @property {boolean} outputMarkdown
56-
* @property {string} pkgName
57-
* @property {string} pkgVersion
58+
* @property {string[]} packages
5859
* @property {boolean} strict
59-
* @property {string} ecosystem
60-
* @property {boolean} includeLicense
6160
*/
6261

6362
/**
@@ -76,14 +75,14 @@ function setupCommand (name, description, argv, importMeta) {
7675

7776
const cli = meow(`
7877
Usage
79-
$ ${name} <ecosystem> <name>
78+
$ ${name} <ecosystem>:<name>@<version>
8079
8180
Options
8281
${printFlagList(flags, 6)}
8382
8483
Examples
85-
$ ${name} npm webtorrent
86-
$ ${name} npm [email protected]
84+
$ ${name} npm:webtorrent
85+
$ ${name} npm:[email protected]
8786
`, {
8887
argv,
8988
description,
@@ -93,75 +92,85 @@ function setupCommand (name, description, argv, importMeta) {
9392

9493
const {
9594
alerts: includeAlerts,
96-
license: includeLicense,
9795
json: outputJson,
9896
markdown: outputMarkdown,
9997
strict,
10098
} = cli.flags
10199

102-
const [ecosystem = '', rawPkgName = ''] = cli.input
100+
const [rawPkgName = ''] = cli.input
103101

104-
if (!ecosystem && !rawPkgName) {
105-
console.error('Please provide an ecosystem and a package name')
102+
if (!rawPkgName) {
103+
console.error('Please provide an ecosystem and package name')
106104
cli.showHelp()
107105
return
108106
}
109107

110-
const versionSeparator = rawPkgName.lastIndexOf('@')
108+
const /** @type {string[]} */inputPkgs = []
111109

112-
const pkgName = versionSeparator < 1 ? rawPkgName : rawPkgName.slice(0, versionSeparator)
113-
const pkgVersion = versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1)
110+
cli.input.map(pkg => {
111+
const ecosystem = pkg.split(':')[0]
112+
if (!ecosystem) {
113+
console.error(`Package name ${pkg} formatted incorrectly.`)
114+
return cli.showHelp()
115+
} else {
116+
const versionSeparator = pkg.lastIndexOf('@')
117+
const ecosystemSeparator = pkg.lastIndexOf(ecosystem)
118+
const pkgName = versionSeparator < 1 ? pkg.slice(ecosystemSeparator + ecosystem.length + 1) : pkg.slice(ecosystemSeparator + ecosystem.length + 1, versionSeparator)
119+
const pkgVersion = versionSeparator < 1 ? 'latest' : pkg.slice(versionSeparator + 1)
120+
inputPkgs.push(`${ecosystem}/${pkgName}@${pkgVersion}`)
121+
}
122+
return inputPkgs
123+
})
114124

115125
return {
116126
includeAlerts,
117-
includeLicense,
118127
outputJson,
119128
outputMarkdown,
120-
pkgName,
121-
pkgVersion,
129+
packages: inputPkgs,
122130
strict,
123-
ecosystem
124131
}
125132
}
126133

127134
/**
128135
* @typedef PackageData
129136
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'batchPackageFetch'>["data"]} data
130-
* @property {Record<import('../../utils/format-issues.js').SocketIssue['severity'], number> | undefined} severityCount
131137
*/
132138

133139
/**
134-
* @param {string} ecosystem
135-
* @param {string} pkgName
136-
* @param {string} pkgVersion
137-
* @param {Pick<CommandContext, 'includeAlerts' | 'includeLicense'>} context
140+
* @param {string[]} packages
141+
* @param {boolean} includeAlerts
138142
* @param {import('ora').Ora} spinner
139143
* @returns {Promise<void|PackageData>}
140144
*/
141-
async function fetchPackageData (ecosystem, pkgName, pkgVersion, { includeAlerts, includeLicense }, spinner) {
145+
async function fetchPackageData (packages, includeAlerts, spinner) {
142146
const socketSdk = await setupSdk(getDefaultKey() || FREE_API_KEY)
147+
148+
const components = packages.map(pkg => {
149+
return { 'purl': `pkg:${pkg}` }
150+
})
151+
143152
// @ts-ignore
144153
const result = await handleApiCall(socketSdk.batchPackageFetch(
145-
{ license: includeLicense.toString(), alerts: includeAlerts.toString() },
154+
{ alerts: includeAlerts.toString() },
146155
{
147-
components:
148-
[{
149-
'purl': `pkg:${ecosystem}/${pkgName}@${pkgVersion}`
150-
}]
156+
components
151157
}), 'looking up package')
152158

153159
if (!result.success) {
154160
return handleUnsuccessfulApiResponse('batchPackageFetch', result, spinner)
155161
}
156162

157163
// @ts-ignore
158-
const severityCount = result.data.alerts && getCountSeverity(result.data.alerts, includeAlerts ? undefined : 'high')
164+
result.data.map(pkg => {
165+
const severityCount = pkg.alerts && getCountSeverity(pkg.alerts, includeAlerts ? undefined : 'high')
166+
pkg.severityCount = severityCount
167+
return pkg
168+
})
159169

160170
spinner.stop()
161171

162172
return {
163-
data: result.data,
164-
severityCount
173+
data: result.data
165174
}
166175
}
167176

@@ -171,52 +180,57 @@ async function fetchPackageData (ecosystem, pkgName, pkgVersion, { includeAlerts
171180
* @param {import('ora').Ora} spinner
172181
* @returns {void}
173182
*/
174-
function formatPackageDataOutput (/** @type {{ [key: string]: any }} */ { data, severityCount }, { name, outputJson, outputMarkdown, pkgName, pkgVersion, strict }, spinner) {
183+
function formatPackageDataOutput (/** @type {{ [key: string]: any }} */ { data }, { outputJson, outputMarkdown, strict }, spinner) {
175184
if (outputJson) {
176185
console.log(JSON.stringify(data, undefined, 2))
177186
} else {
178-
console.log('\nPackage metrics:')
179-
180-
const scoreResult = {
181-
'Supply Chain Risk': Math.floor(data.score.supplyChain * 100),
182-
'Maintenance': Math.floor(data.score.maintenance * 100),
183-
'Quality': Math.floor(data.score.quality * 100),
184-
'Vulnerabilities': Math.floor(data.score.vulnerability * 100),
185-
'License': Math.floor(data.score.license * 100),
186-
'Overall': Math.floor(data.score.overall * 100)
187-
}
188-
Object.entries(scoreResult).map(score => console.log(`- ${score[0]}: ${formatScore(score[1])}`))
189-
190-
// Package license
191-
console.log('\nPackage license:')
192-
console.log(`${data.license}`)
193-
194-
// Package issues list
195-
if (objectSome(severityCount)) {
196-
const issueSummary = formatSeverityCount(severityCount)
197-
console.log('\n')
198-
spinner[strict ? 'fail' : 'succeed'](`Package has these issues: ${issueSummary}`)
199-
formatPackageIssuesDetails(data.alerts, outputMarkdown)
200-
} else if (severityCount && !objectSome(severityCount)) {
201-
console.log('\n')
202-
spinner.succeed('Package has no issues')
203-
}
187+
data.map((/** @type {{[key:string]: any}} */ d) => {
188+
const { score, license, name, severityCount, version } = d
189+
console.log(`\nPackage metrics for ${name}:`)
190+
191+
const scoreResult = {
192+
'Supply Chain Risk': Math.floor(score.supplyChain * 100),
193+
'Maintenance': Math.floor(score.maintenance * 100),
194+
'Quality': Math.floor(score.quality * 100),
195+
'Vulnerabilities': Math.floor(score.vulnerability * 100),
196+
'License': Math.floor(score.license * 100),
197+
'Overall': Math.floor(score.overall * 100)
198+
}
204199

205-
// Link to issues list
206-
const format = new ChalkOrMarkdown(!!outputMarkdown)
207-
const url = `https://socket.dev/npm/package/${pkgName}/overview/${pkgVersion}`
208-
if (pkgVersion === 'latest') {
209-
console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${pkgName}`, url, { fallbackToUrl: true }))
210-
} else {
211-
console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${pkgName} v${pkgVersion}`, url, { fallbackToUrl: true }))
212-
}
213-
if (!outputMarkdown) {
214-
console.log(chalk.dim('\nOr rerun', chalk.italic(name), 'using the', chalk.italic('--json'), 'flag to get full JSON output'))
215-
}
216-
}
200+
Object.entries(scoreResult).map(score => console.log(`- ${score[0]}: ${formatScore(score[1])}`))
201+
202+
// Package license
203+
console.log('\nPackage license:')
204+
console.log(`${license}`)
205+
206+
// Package issues list
207+
if (objectSome(severityCount)) {
208+
const issueSummary = formatSeverityCount(severityCount)
209+
console.log('\n')
210+
spinner[strict ? 'fail' : 'succeed'](`Package has these issues: ${issueSummary}`)
211+
formatPackageIssuesDetails(data.alerts, outputMarkdown)
212+
} else if (severityCount && !objectSome(severityCount)) {
213+
console.log('\n')
214+
spinner.succeed('Package has no issues')
215+
}
217216

218-
if (strict && objectSome(severityCount)) {
219-
process.exit(1)
217+
// Link to issues list
218+
const format = new ChalkOrMarkdown(!!outputMarkdown)
219+
const url = `https://socket.dev/npm/package/${name}/overview/${version}`
220+
if (version === 'latest') {
221+
console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${name}`, url, { fallbackToUrl: true }))
222+
} else {
223+
console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${name} v${version}`, url, { fallbackToUrl: true }))
224+
}
225+
if (!outputMarkdown) {
226+
console.log(chalk.dim('\nOr rerun', chalk.italic(name), 'using the', chalk.italic('--json'), 'flag to get full JSON output'))
227+
}
228+
229+
if (strict && objectSome(severityCount)) {
230+
process.exit(1)
231+
}
232+
return d
233+
})
220234
}
221235
}
222236

0 commit comments

Comments
 (0)