@@ -359,9 +359,9 @@ func NewFirewallAuditCmd(f *cmdutils.Factory) *cobra.Command {
359359
360360// validateFileForPackageType validates that the dependency file matches the registry package type
361361func validateFileForPackageType (fileName , packageType string ) error {
362- // Define valid files for each package type
363362 validFiles := map [string ][]string {
364363 "NPM" : {
364+ "package.json" ,
365365 "package-lock.json" ,
366366 "yarn.lock" ,
367367 "pnpm-lock.yaml" ,
@@ -379,13 +379,11 @@ func validateFileForPackageType(fileName, packageType string) error {
379379 },
380380 }
381381
382- // Get valid files for the package type
383382 validFilesList , ok := validFiles [packageType ]
384383 if ! ok {
385384 return fmt .Errorf ("unsupported package type: %s (supported: NPM, PYTHON, MAVEN)" , packageType )
386385 }
387386
388- // Check if the file is valid for this package type
389387 for _ , validFile := range validFilesList {
390388 if fileName == validFile || strings .HasSuffix (fileName , validFile ) {
391389 return nil
@@ -405,6 +403,8 @@ func parseLockFile(filePath string) ([]Dependency, error) {
405403 fileName := filepath .Base (filePath )
406404
407405 switch {
406+ case fileName == "package.json" :
407+ return parsePackageJson (data )
408408 case strings .HasSuffix (fileName , "package-lock.json" ):
409409 return parsePackageLock (data )
410410 case strings .HasSuffix (fileName , "pnpm-lock.yaml" ):
@@ -424,10 +424,91 @@ func parseLockFile(filePath string) ([]Dependency, error) {
424424 case strings .HasSuffix (fileName , "build.gradle" ) || strings .HasSuffix (fileName , "build.gradle.kts" ):
425425 return parseBuildGradle (data )
426426 default :
427- return nil , fmt .Errorf ("unsupported lock file format: %s (supported: package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, pyproject.toml, Pipfile.lock, poetry.lock, pom.xml, build.gradle)" , fileName )
427+ return nil , fmt .Errorf ("unsupported dependency file format: %s (supported: package.json, package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, pyproject.toml, Pipfile.lock, poetry.lock, pom.xml, build.gradle)" , fileName )
428428 }
429429}
430430
431+ func parsePackageJson (data []byte ) ([]Dependency , error ) {
432+ var pkgJson struct {
433+ Dependencies map [string ]string `json:"dependencies"`
434+ DevDependencies map [string ]string `json:"devDependencies"`
435+ PeerDependencies map [string ]string `json:"peerDependencies"`
436+ OptionalDependencies map [string ]string `json:"optionalDependencies"`
437+ }
438+
439+ if err := json .Unmarshal (data , & pkgJson ); err != nil {
440+ return nil , fmt .Errorf ("failed to parse package.json: %w" , err )
441+ }
442+
443+ deps := make ([]Dependency , 0 )
444+ seen := make (map [string ]bool )
445+
446+ cleanVersion := func (version string ) string {
447+ version = strings .TrimSpace (version )
448+ version = strings .TrimPrefix (version , "^" )
449+ version = strings .TrimPrefix (version , "~" )
450+ version = strings .TrimPrefix (version , ">=" )
451+ version = strings .TrimPrefix (version , ">" )
452+ version = strings .TrimPrefix (version , "<=" )
453+ version = strings .TrimPrefix (version , "<" )
454+ version = strings .TrimPrefix (version , "=" )
455+ if idx := strings .Index (version , " " ); idx != - 1 {
456+ version = version [:idx ]
457+ }
458+ return version
459+ }
460+
461+ for name , version := range pkgJson .Dependencies {
462+ if seen [name ] {
463+ continue
464+ }
465+ seen [name ] = true
466+ deps = append (deps , Dependency {
467+ Name : name ,
468+ Version : cleanVersion (version ),
469+ Source : "package.json" ,
470+ })
471+ }
472+
473+ for name , version := range pkgJson .DevDependencies {
474+ if seen [name ] {
475+ continue
476+ }
477+ seen [name ] = true
478+ deps = append (deps , Dependency {
479+ Name : name ,
480+ Version : cleanVersion (version ),
481+ Source : "package.json" ,
482+ })
483+ }
484+
485+ for name , version := range pkgJson .PeerDependencies {
486+ if seen [name ] {
487+ continue
488+ }
489+ seen [name ] = true
490+ deps = append (deps , Dependency {
491+ Name : name ,
492+ Version : cleanVersion (version ),
493+ Source : "package.json" ,
494+ })
495+ }
496+
497+ for name , version := range pkgJson .OptionalDependencies {
498+ if seen [name ] {
499+ continue
500+ }
501+ seen [name ] = true
502+ deps = append (deps , Dependency {
503+ Name : name ,
504+ Version : cleanVersion (version ),
505+ Source : "package.json" ,
506+ })
507+ }
508+
509+ return deps , nil
510+ }
511+
431512func parsePackageLock (data []byte ) ([]Dependency , error ) {
432513 var lockFile struct {
433514 LockfileVersion int `json:"lockfileVersion"`
0 commit comments