@@ -9,6 +9,13 @@ class PackageDependencyExtractor {
9
9
dependencyMap : Map < string , Set < string > > = new Map ( ) ;
10
10
artifactMap : Map < string , Set < string > > = new Map ( ) ;
11
11
basePackageDependencyMap : Map < string , Set < string > > = new Map ( ) ;
12
+ // Add property to track library counts
13
+ libraryCounts = {
14
+ struts : 0 ,
15
+ commons : 0 ,
16
+ log4j : 0 ,
17
+ cryptix : 0
18
+ } ;
12
19
13
20
async parseJsonlFile ( filePath : string ) : Promise < void > {
14
21
// In our tests, we don't actually read from a file
@@ -71,6 +78,9 @@ class PackageDependencyExtractor {
71
78
}
72
79
this . artifactMap . get ( record . artifactId ) ! . add ( sourcePackage ) ;
73
80
this . artifactMap . get ( record . artifactId ) ! . add ( targetPackage ) ;
81
+
82
+ // Count specific libraries in targetClass
83
+ this . countSpecificLibraries ( targetClass ) ;
74
84
}
75
85
76
86
getPackageName ( className : string ) : string {
@@ -174,6 +184,16 @@ class PackageDependencyExtractor {
174
184
let markdownContent = '# Project Package Dependencies\n\n' ;
175
185
markdownContent += 'This document lists all base packages that the project depends on.\n\n' ;
176
186
187
+ // Add section for specific library counts
188
+ markdownContent += '## Specific Library Counts\n\n' ;
189
+ markdownContent += 'These counts represent the number of dependencies where the `targetClass` field in the JSONL data contains each specific library name. This helps quantify how many times your application code depends on classes from these libraries, which is useful for identifying vulnerability exposure.\n\n' ;
190
+ markdownContent += '| Library | Count |\n' ;
191
+ markdownContent += '|---------|-------|\n' ;
192
+ markdownContent += `| Struts | ${ this . libraryCounts . struts } |\n` ;
193
+ markdownContent += `| Commons | ${ this . libraryCounts . commons } |\n` ;
194
+ markdownContent += `| Log4j | ${ this . libraryCounts . log4j } |\n` ;
195
+ markdownContent += `| Cryptix | ${ this . libraryCounts . cryptix } |\n\n` ;
196
+
177
197
// List all base packages
178
198
markdownContent += '## Base Packages\n\n' ;
179
199
@@ -267,6 +287,28 @@ class PackageDependencyExtractor {
267
287
// Use fs.writeFileSync to write the output
268
288
fs . writeFileSync ( outputFile , markdownContent ) ;
269
289
}
290
+
291
+ // Method to count instances of specific libraries
292
+ countSpecificLibraries ( targetClass : string ) : void {
293
+ // Check for each specific library in the targetClass
294
+ if ( targetClass . toLowerCase ( ) . includes ( 'struts' ) ) {
295
+ this . libraryCounts . struts ++ ;
296
+ }
297
+ if ( targetClass . toLowerCase ( ) . includes ( 'commons' ) ) {
298
+ this . libraryCounts . commons ++ ;
299
+ }
300
+ if ( targetClass . toLowerCase ( ) . includes ( 'log4j' ) ) {
301
+ this . libraryCounts . log4j ++ ;
302
+ }
303
+ if ( targetClass . toLowerCase ( ) . includes ( 'cryptix' ) ) {
304
+ this . libraryCounts . cryptix ++ ;
305
+ }
306
+ }
307
+
308
+ // Getter for library counts (useful for testing)
309
+ getLibraryCounts ( ) {
310
+ return this . libraryCounts ;
311
+ }
270
312
}
271
313
272
314
// Create a mock for fs module
@@ -616,4 +658,94 @@ describe('PackageDependencyExtractor', () => {
616
658
process . env . NODE_ENV = originalNodeEnv ;
617
659
} ) ;
618
660
} ) ;
661
+ } ) ;
662
+
663
+ // Add tests for library counts
664
+ describe ( 'countSpecificLibraries' , ( ) => {
665
+ test ( 'should count struts in targetClass' , ( ) => {
666
+ const extractor = new PackageDependencyExtractor ( ) ;
667
+ extractor . countSpecificLibraries ( 'org.apache.struts.actions.Action' ) ;
668
+ expect ( extractor . libraryCounts . struts ) . toBe ( 1 ) ;
669
+ } ) ;
670
+
671
+ test ( 'should count commons in targetClass' , ( ) => {
672
+ const extractor = new PackageDependencyExtractor ( ) ;
673
+ extractor . countSpecificLibraries ( 'org.apache.commons.lang.StringUtils' ) ;
674
+ expect ( extractor . libraryCounts . commons ) . toBe ( 1 ) ;
675
+ } ) ;
676
+
677
+ test ( 'should count log4j in targetClass' , ( ) => {
678
+ const extractor = new PackageDependencyExtractor ( ) ;
679
+ extractor . countSpecificLibraries ( 'org.apache.log4j.Logger' ) ;
680
+ expect ( extractor . libraryCounts . log4j ) . toBe ( 1 ) ;
681
+ } ) ;
682
+
683
+ test ( 'should count cryptix in targetClass' , ( ) => {
684
+ const extractor = new PackageDependencyExtractor ( ) ;
685
+ extractor . countSpecificLibraries ( 'cryptix.provider.Cipher' ) ;
686
+ expect ( extractor . libraryCounts . cryptix ) . toBe ( 1 ) ;
687
+ } ) ;
688
+
689
+ test ( 'should handle case insensitivity' , ( ) => {
690
+ const extractor = new PackageDependencyExtractor ( ) ;
691
+ extractor . countSpecificLibraries ( 'org.apache.STRUTS.Action' ) ;
692
+ extractor . countSpecificLibraries ( 'org.apache.COMMONS.FileUtils' ) ;
693
+ extractor . countSpecificLibraries ( 'org.apache.LOG4J.Logger' ) ;
694
+ extractor . countSpecificLibraries ( 'CRYPTIX.provider.Cipher' ) ;
695
+
696
+ expect ( extractor . libraryCounts . struts ) . toBe ( 1 ) ;
697
+ expect ( extractor . libraryCounts . commons ) . toBe ( 1 ) ;
698
+ expect ( extractor . libraryCounts . log4j ) . toBe ( 1 ) ;
699
+ expect ( extractor . libraryCounts . cryptix ) . toBe ( 1 ) ;
700
+ } ) ;
701
+
702
+ test ( 'should handle multiple libraries in one targetClass' , ( ) => {
703
+ const extractor = new PackageDependencyExtractor ( ) ;
704
+ extractor . countSpecificLibraries ( 'org.apache.struts.commons.util' ) ;
705
+
706
+ expect ( extractor . libraryCounts . struts ) . toBe ( 1 ) ;
707
+ expect ( extractor . libraryCounts . commons ) . toBe ( 1 ) ;
708
+ expect ( extractor . libraryCounts . log4j ) . toBe ( 0 ) ;
709
+ expect ( extractor . libraryCounts . cryptix ) . toBe ( 0 ) ;
710
+ } ) ;
711
+
712
+ test ( 'should increment counts correctly for multiple calls' , ( ) => {
713
+ const extractor = new PackageDependencyExtractor ( ) ;
714
+ extractor . countSpecificLibraries ( 'org.apache.struts.Action' ) ;
715
+ extractor . countSpecificLibraries ( 'org.apache.struts.actions.DispatchAction' ) ;
716
+ extractor . countSpecificLibraries ( 'org.apache.commons.lang.StringUtils' ) ;
717
+ extractor . countSpecificLibraries ( 'org.apache.commons.io.FileUtils' ) ;
718
+
719
+ expect ( extractor . libraryCounts . struts ) . toBe ( 2 ) ;
720
+ expect ( extractor . libraryCounts . commons ) . toBe ( 2 ) ;
721
+ } ) ;
722
+ } ) ;
723
+
724
+ // Add test for processRecord with library counting
725
+ test ( 'should count libraries when processing a record' , ( ) => {
726
+ const extractor = new PackageDependencyExtractor ( ) ;
727
+ const record = {
728
+ appSetName : 'TestApp' ,
729
+ applicationName : 'TestApp' ,
730
+ artifactFileName : 'test.jar' ,
731
+ artifactId : 'test' ,
732
+ artifactGroup : 'com.test' ,
733
+ artifactVersion : '1.0.0' ,
734
+ sourceClass : 'com.test.TestClass' ,
735
+ sourceMethod : 'testMethod' ,
736
+ targetClass : 'org.apache.struts.Action' ,
737
+ targetMethod : 'execute'
738
+ } ;
739
+
740
+ extractor . processRecord ( record ) ;
741
+ expect ( extractor . libraryCounts . struts ) . toBe ( 1 ) ;
742
+
743
+ // Process another record with a different library
744
+ const record2 = {
745
+ ...record ,
746
+ targetClass : 'org.apache.commons.lang.StringUtils'
747
+ } ;
748
+
749
+ extractor . processRecord ( record2 ) ;
750
+ expect ( extractor . libraryCounts . commons ) . toBe ( 1 ) ;
619
751
} ) ;
0 commit comments