@@ -13,12 +13,17 @@ import { describe, expect, it } from 'vitest'
1313
1414import {
1515 flattenReportAlerts ,
16+ isFullScanReport ,
1617 toPlainTextReport ,
1718} from '../../../../src/command/scan/output-scan-report.mts'
1819
1920import type {
21+ EcoMap ,
22+ FileMap ,
23+ PackageMap ,
2024 ReportLeafNode ,
2125 ScanReport ,
26+ VersionMap ,
2227} from '../../../../src/command/scan/generate-report.mts'
2328
2429// Matches any ANSI escape sequence, the codes that show up as literal noise
@@ -27,6 +32,15 @@ import type {
2732// oxlint-disable-next-line no-control-regex -- control chars intended
2833const ANSI_PATTERN = / \u001B \[ [ 0 - 9 ; ] * m /
2934
35+ describe ( 'isFullScanReport' , ( ) => {
36+ it ( 'distinguishes full reports from short reports' , ( ) => {
37+ expect (
38+ isFullScanReport ( buildReport ( { alerts : new Map ( ) , healthy : true } ) ) ,
39+ ) . toBe ( true )
40+ expect ( isFullScanReport ( { healthy : true } ) ) . toBe ( false )
41+ } )
42+ } )
43+
3044function buildReport ( config : {
3145 alerts : ScanReport [ 'alerts' ]
3246 healthy : boolean
@@ -42,30 +56,33 @@ function buildReport(config: {
4256}
4357
4458function buildAlerts ( ) : ScanReport [ 'alerts' ] {
45- return new Map ( [
46- [
47- 'npm' ,
48- new Map ( [
49- [
50- 'acme-widget' ,
51- new Map ( [
52- [
53- '1.0.0' ,
54- {
55- manifest : [ 'package.json' ] ,
56- policy : 'error' ,
57- type : 'envVars' ,
58- url : 'https://socket.dev/npm/package/acme-widget' ,
59- } ,
60- ] ,
61- ] ) ,
62- ] ,
63- ] ) ,
64- ] ,
65- ] ) as unknown as ScanReport [ 'alerts' ]
59+ const leaf : ReportLeafNode = {
60+ manifest : [ 'package.json' ] ,
61+ policy : 'error' ,
62+ type : 'envVars' ,
63+ url : 'https://socket.dev/npm/package/acme-widget' ,
64+ }
65+ const fileMap : FileMap = new Map ( [ [ 'envVars at 1:2' , leaf ] ] )
66+ const versionMap : VersionMap = new Map ( [ [ 'package.json' , fileMap ] ] )
67+ const packageMap : PackageMap = new Map ( [ [ '1.0.0' , versionMap ] ] )
68+ const ecosystemMap : EcoMap = new Map ( [ [ 'acme-widget' , packageMap ] ] )
69+
70+ return new Map ( [ [ 'npm' , ecosystemMap ] ] )
6671}
6772
6873describe ( 'toPlainTextReport' , ( ) => {
74+ it ( 'labels the package version as a version' , ( ) => {
75+ const report = buildReport ( { alerts : buildAlerts ( ) , healthy : false } )
76+ const text = toPlainTextReport ( report )
77+
78+ expect ( flattenReportAlerts ( report ) [ 0 ] ) . toMatchObject ( {
79+ packageVersion : '1.0.0' ,
80+ } )
81+ expect ( text ) . toContain ( 'VERSION' )
82+ expect ( text ) . toContain ( '1.0.0' )
83+ expect ( text ) . not . toContain ( 'INTRODUCED BY' )
84+ } )
85+
6986 it ( 'emits no ANSI escape codes' , ( ) => {
7087 const text = toPlainTextReport (
7188 buildReport ( { alerts : buildAlerts ( ) , healthy : false } ) ,
@@ -237,6 +254,123 @@ describe('toPlainTextReport', () => {
237254
238255 expect ( text ) . toContain ( 'No alerts' )
239256 expect ( text ) . not . toContain ( 'ALERT TYPE' )
257+ expect ( text ) . not . toContain ( 'VERSION' )
258+ } )
259+
260+ it ( 'retains package versions for version and file folds' , ( ) => {
261+ const versionLeaf : ReportLeafNode = {
262+ manifest : [ 'package.json' ] ,
263+ policy : 'error' ,
264+ type : 'envVars' ,
265+ url : '' ,
266+ }
267+ const versionFoldAlerts : ScanReport [ 'alerts' ] = new Map ( [
268+ [
269+ 'npm' ,
270+ new Map ( [ [ 'demo-transitive' , new Map ( [ [ '2.3.4' , versionLeaf ] ] ) ] ] ) ,
271+ ] ,
272+ ] )
273+ const fileFoldAlerts : ScanReport [ 'alerts' ] = new Map ( [
274+ [
275+ 'npm' ,
276+ new Map ( [
277+ [
278+ 'demo-transitive' ,
279+ new Map ( [
280+ [
281+ '2.3.4' ,
282+ new Map ( [
283+ [ 'package.json' , versionLeaf ] ,
284+ [
285+ 'src/index.js' ,
286+ { ...versionLeaf , manifest : [ 'package-lock.json' ] } ,
287+ ] ,
288+ ] ) ,
289+ ] ,
290+ ] ) ,
291+ ] ,
292+ ] ) ,
293+ ] ,
294+ ] )
295+ const versionFoldReport = {
296+ ...buildReport ( { alerts : versionFoldAlerts , healthy : false } ) ,
297+ options : { fold : 'version' as const , reportLevel : 'error' as const } ,
298+ }
299+ const fileFoldReport = {
300+ ...buildReport ( { alerts : fileFoldAlerts , healthy : false } ) ,
301+ options : { fold : 'file' as const , reportLevel : 'error' as const } ,
302+ }
303+
304+ expect ( flattenReportAlerts ( versionFoldReport ) [ 0 ] ?. packageVersion ) . toBe (
305+ '2.3.4' ,
306+ )
307+ expect ( toPlainTextReport ( versionFoldReport ) ) . toContain ( 'VERSION' )
308+ expect ( toPlainTextReport ( versionFoldReport ) ) . toContain ( '2.3.4' )
309+ expect ( flattenReportAlerts ( fileFoldReport ) ) . toEqual ( [
310+ expect . objectContaining ( {
311+ manifest : 'package.json' ,
312+ packageVersion : '2.3.4' ,
313+ } ) ,
314+ expect . objectContaining ( {
315+ manifest : 'package-lock.json' ,
316+ packageVersion : '2.3.4' ,
317+ } ) ,
318+ ] )
319+ expect ( toPlainTextReport ( fileFoldReport ) ) . toContain ( 'VERSION' )
320+ expect ( toPlainTextReport ( fileFoldReport ) ) . toContain ( '2.3.4' )
321+ expect ( toPlainTextReport ( fileFoldReport ) ) . toContain ( 'package-lock.json' )
322+ } )
323+
324+ it ( 'keeps package-fold versions unknown and distinguishes package versions' , ( ) => {
325+ const leaf : ReportLeafNode = {
326+ manifest : [ 'package.json' ] ,
327+ policy : 'error' ,
328+ type : 'envVars' ,
329+ url : '' ,
330+ }
331+ const packageFoldAlerts : ScanReport [ 'alerts' ] = new Map ( [
332+ [ 'npm' , new Map ( [ [ 'demo-transitive' , leaf ] ] ) ] ,
333+ ] )
334+ const twoVersionAlerts : ScanReport [ 'alerts' ] = new Map ( [
335+ [
336+ 'npm' ,
337+ new Map ( [
338+ [
339+ 'demo-transitive' ,
340+ new Map ( [
341+ [
342+ '2.3.4' ,
343+ new Map ( [
344+ [ 'package.json' , new Map ( [ [ 'envVars at 1:2' , leaf ] ] ) ] ,
345+ ] ) ,
346+ ] ,
347+ [
348+ '2.3.5' ,
349+ new Map ( [
350+ [ 'package.json' , new Map ( [ [ 'envVars at 3:4' , leaf ] ] ) ] ,
351+ ] ) ,
352+ ] ,
353+ ] ) ,
354+ ] ,
355+ ] ) ,
356+ ] ,
357+ ] )
358+ const packageFoldReport = {
359+ ...buildReport ( { alerts : packageFoldAlerts , healthy : false } ) ,
360+ options : { fold : 'pkg' as const , reportLevel : 'error' as const } ,
361+ }
362+ const twoVersionReport = {
363+ ...buildReport ( { alerts : twoVersionAlerts , healthy : false } ) ,
364+ options : { fold : 'none' as const , reportLevel : 'error' as const } ,
365+ }
366+
367+ expect ( flattenReportAlerts ( packageFoldReport ) [ 0 ] ?. packageVersion ) . toBe (
368+ '<unknown>' ,
369+ )
370+ expect ( toPlainTextReport ( packageFoldReport ) ) . toContain ( '<unknown>' )
371+ expect (
372+ flattenReportAlerts ( twoVersionReport ) . map ( row => row . packageVersion ) ,
373+ ) . toEqual ( [ '2.3.4' , '2.3.5' ] )
240374 } )
241375} )
242376
@@ -249,9 +383,9 @@ describe('flattenReportAlerts', () => {
249383 expect ( rows ) . toEqual ( [
250384 {
251385 alertType : 'envVars' ,
252- introducedBy : '1.0.0' ,
253386 manifest : 'package.json' ,
254387 packageName : 'acme-widget' ,
388+ packageVersion : '1.0.0' ,
255389 policy : 'error' ,
256390 url : 'https://socket.dev/npm/package/acme-widget' ,
257391 } ,
0 commit comments