1- /* eslint-disable max-depth */
21// Import Node.js Dependencies
32import fs from "node:fs" ;
43
54// Import Third-party Dependencies
6- import { formatBytes , getScoreColor , getVCSRepositoryPathAndPlatform } from "@nodesecure/utils" ;
5+ import { getScoreColor , getVCSRepositoryPathAndPlatform } from "@nodesecure/utils" ;
76import { getManifest , getFlags } from "@nodesecure/flags/web" ;
87import * as scorecard from "@nodesecure/ossf-scorecard-sdk" ;
9- import type { Payload } from "@nodesecure/scanner" ;
8+ import { Extractors , type Payload , type Dependency , type DependencyVersion , type DependencyLinks } from "@nodesecure/scanner" ;
109import type { RC } from "@nodesecure/rc" ;
1110
1211// Import Internal Dependencies
@@ -62,11 +61,6 @@ export async function buildStatsFromScannerDependencies(
6261 const { reportConfig } = options ;
6362
6463 const config = reportConfig ?? localStorage . getConfig ( ) . report ! ;
65- const sizeStats = {
66- all : 0 ,
67- internal : 0 ,
68- external : 0
69- } ;
7064
7165 const stats : ReportStat = {
7266 size : {
@@ -111,86 +105,80 @@ export async function buildStatsFromScannerDependencies(
111105
112106 const payloads = Array . isArray ( payloadFiles ) ? payloadFiles : [ payloadFiles ] ;
113107 const npmConfig = config . npm ! ;
114- for ( const fileOrJson of payloads ) {
115- const dependencies = getPayloadDependencies ( fileOrJson ) ;
116-
117- for ( const [ name , descriptor ] of Object . entries ( dependencies ) ) {
118- const { versions, metadata } = descriptor ;
119- const isThird = npmConfig . organizationPrefix === null ?
120- true :
121- ! name . startsWith ( `${ npmConfig . organizationPrefix } /` ) ;
122-
123- for ( const human of metadata . maintainers ) {
124- if ( human . email ) {
125- stats . authors [ human . email ] = human . email in stats . authors ?
126- ++ stats . authors [ human . email ] : 1 ;
127- }
128- }
129108
130- if ( ! ( name in stats . packages ) ) {
131- const { orgPrefix, name : splitName } = splitPackageWithOrg ( name ) ;
132- const isGiven = config . npm ?. packages . includes ( splitName ) && orgPrefix === config . npm ?. organizationPrefix ;
133- if ( isThird ) {
134- stats . packages_count . external ++ ;
135- }
136- stats . packages [ name ] = { isThird, versions : new Set ( ) , fullName : name , isGiven, flags : { } } ;
109+ const dependencies = payloads . reduce < Payload [ "dependencies" ] > ( ( acc , curr ) => {
110+ const dep = getPayloadDependencies ( curr ) ;
111+ Object . assign ( acc , dep ) ;
112+
113+ return acc ;
114+ } , { } ) ;
115+
116+ const extractor = new Extractors . Payload ( dependencies , [
117+ new Extractors . Probes . Contacts ( ) ,
118+ new Extractors . Probes . Flags ( ) ,
119+ new Extractors . Probes . Licenses ( ) ,
120+ new Extractors . Probes . Warnings ( ) ,
121+ new Extractors . Probes . Size ( { organizationPrefix : npmConfig . organizationPrefix } ) ,
122+ new Extractors . Probes . Extensions ( ) ,
123+ new Extractors . Probes . NodeDependencies ( )
124+ ] ) ;
125+
126+ extractor . on ( "manifest" , ( spec : string ,
127+ { flags, links = [ ] } : Omit < DependencyVersion , "links" > & {
128+ links : DependencyLinks | never [ ] ;
129+ } ,
130+ { name } : { name : string ; dependency : Dependency ; } ) => {
131+ const isThird = npmConfig . organizationPrefix === null ?
132+ true :
133+ ! name . startsWith ( `${ npmConfig . organizationPrefix } /` ) ;
134+ if ( ! ( name in stats . packages ) ) {
135+ const { orgPrefix, name : splitName } = splitPackageWithOrg ( name ) ;
136+ const isGiven = config . npm ?. packages . includes ( splitName ) && orgPrefix === config . npm ?. organizationPrefix ;
137+ if ( isThird ) {
138+ stats . packages_count . external ++ ;
137139 }
140+ stats . packages [ name ] = { isThird, versions : new Set ( ) , fullName : name , isGiven, flags : { } } ;
141+ }
142+ const curr = stats . packages [ name ] ;
143+ if ( curr . versions . has ( spec ) ) {
144+ return ;
145+ }
138146
139- const curr = stats . packages [ name ] ;
140- for ( const [ localVersion , localDescriptor ] of Object . entries ( versions ) ) {
141- if ( curr . versions . has ( localVersion ) ) {
142- continue ;
143- }
144- const { flags, size, composition, uniqueLicenseIds, author, warnings = [ ] , links = [ ] } = localDescriptor ;
145-
146- sizeStats . all += size ;
147- sizeStats [ isThird ? "external" : "internal" ] += size ;
148-
149- for ( const { kind } of warnings ) {
150- stats . warnings [ kind ] = kind in stats . warnings ? ++ stats . warnings [ kind ] : 1 ;
151- }
152-
153- for ( const flag of flags ) {
154- if ( ! ( flag in kWantedFlags ) ) {
155- continue ;
156- }
157- stats . flags [ flag ] = flag in stats . flags ? ++ stats . flags [ flag ] : 1 ;
158- stats . packages [ name ] . flags [ flag ] = { ...stats . flagsList [ flag ] } ;
159- }
160-
161- ( composition . required_nodejs )
162- . forEach ( ( dep ) => ( stats . deps . node [ dep ] = { visualizerUrl : `${ kNodeVisualizerUrl } /${ dep . replace ( "node:" , "" ) } .html` } ) ) ;
163- for ( const extName of composition . extensions . filter ( ( extName ) => extName !== "" ) ) {
164- stats . extensions [ extName ] = extName in stats . extensions ? ++ stats . extensions [ extName ] : 1 ;
165- }
166-
167- for ( const licenseName of uniqueLicenseIds ) {
168- stats . licenses [ licenseName ] = licenseName in stats . licenses ?
169- ++ stats . licenses [ licenseName ] : 1 ;
170- }
171-
172- if ( author ?. email ) {
173- stats . authors [ author . email ] = author . email in stats . authors ?
174- ++ stats . authors [ author . email ] : 1 ;
175- }
176-
177- curr . versions . add ( localVersion ) ;
178- const hasIndirectDependencies = flags . includes ( "hasIndirectDependencies" ) ;
179- id: if ( hasIndirectDependencies ) {
180- if ( ! config . includeTransitiveInternal && name . startsWith ( npmConfig . organizationPrefix ) ) {
181- break id;
182- }
183-
184- stats . deps . transitive [ `${ name } @${ localVersion } ` ] = { links } ;
185- }
186- curr [ localVersion ] = { hasIndirectDependencies } ;
187-
188- if ( ! curr . links ) {
189- Object . assign ( curr , { links } ) ;
190- }
147+ for ( const flag of flags ) {
148+ if ( ! ( kWantedFlags . has ( flag ) ) ) {
149+ continue ;
191150 }
151+ stats . packages [ name ] . flags [ flag ] = { ...stats . flagsList [ flag ] } ;
192152 }
193- }
153+ curr . versions . add ( spec ) ;
154+ const hasIndirectDependencies = flags . includes ( "hasIndirectDependencies" ) ;
155+ id: if ( hasIndirectDependencies ) {
156+ if ( ! config . includeTransitiveInternal && name . startsWith ( npmConfig . organizationPrefix ) ) {
157+ break id;
158+ }
159+
160+ stats . deps . transitive [ `${ name } @${ spec } ` ] = { links } ;
161+ }
162+ curr [ spec ] = { hasIndirectDependencies } ;
163+
164+ if ( ! curr . links ) {
165+ Object . assign ( curr , { links } ) ;
166+ }
167+ } ) ;
168+
169+ const { contacts, licenses, flags, warnings, size, extensions, nodeDeps } = extractor . extractAndMerge ( ) ;
170+
171+ stats . authors = contacts ;
172+ stats . licenses = { ...stats . licenses , ...licenses } ;
173+ stats . size = size ;
174+ stats . flags = flags ;
175+ stats . warnings = warnings . uniqueKinds ;
176+ stats . extensions = extensions ;
177+ stats . deps . node = nodeDeps . reduce ( ( acc : ReportStat [ "deps" ] [ "node" ] , curr ) => {
178+ Object . assign ( acc , { [ curr ] : { visualizerUrl : `${ kNodeVisualizerUrl } /${ curr . replace ( "node:" , "" ) } .html` } } ) ;
179+
180+ return acc ;
181+ } , { } ) ;
194182
195183 const givenPackages = Object . values ( stats . packages ) . filter ( ( pkg ) => pkg . isGiven ) ;
196184
@@ -207,9 +195,6 @@ export async function buildStatsFromScannerDependencies(
207195
208196 stats . packages_count . all = Object . keys ( stats . packages ) . length ;
209197 stats . packages_count . internal = stats . packages_count . all - stats . packages_count . external ;
210- stats . size . all = formatBytes ( sizeStats . all ) ;
211- stats . size . internal = formatBytes ( sizeStats . internal ) ;
212- stats . size . external = formatBytes ( sizeStats . external ) ;
213198
214199 return stats ;
215200}
0 commit comments