fixed #4430 exclude dev pnpm pkg (#4487)

* fixed #4430 exclude dev pnpm pkg

Signed-off-by: Rez Moss <hi@rezmoss.com>

* use existing dev deps option

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fixed #4430 exclude dev pnpm pkg, add test

Signed-off-by: Rez Moss <hi@rezmoss.com>

* fixed #4430 exclude dev pnpm pkg, add test

Signed-off-by: Rez Moss <hi@rezmoss.com>

---------

Signed-off-by: Rez Moss <hi@rezmoss.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Rez Moss 2026-01-07 10:39:16 -05:00 committed by GitHub
parent 6509b7079e
commit 3a3a86eb01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 6 deletions

View File

@ -25,6 +25,7 @@ type pnpmPackage struct {
Version string Version string
Integrity string Integrity string
Dependencies map[string]string Dependencies map[string]string
Dev bool
} }
// pnpmLockfileParser defines the interface for parsing different versions of pnpm lockfiles. // pnpmLockfileParser defines the interface for parsing different versions of pnpm lockfiles.
@ -35,6 +36,7 @@ type pnpmLockfileParser interface {
type pnpmV6PackageEntry struct { type pnpmV6PackageEntry struct {
Resolution map[string]string `yaml:"resolution"` Resolution map[string]string `yaml:"resolution"`
Dependencies map[string]string `yaml:"dependencies"` Dependencies map[string]string `yaml:"dependencies"`
Dev bool `yaml:"dev"`
} }
// pnpmV6LockYaml represents the structure of pnpm lockfiles for versions < 9.0. // pnpmV6LockYaml represents the structure of pnpm lockfiles for versions < 9.0.
@ -53,6 +55,7 @@ type pnpmV9SnapshotEntry struct {
type pnpmV9PackageEntry struct { type pnpmV9PackageEntry struct {
Resolution map[string]string `yaml:"resolution"` Resolution map[string]string `yaml:"resolution"`
PeerDependencies map[string]string `yaml:"peerDependencies"` PeerDependencies map[string]string `yaml:"peerDependencies"`
Dev bool `yaml:"dev"`
} }
// pnpmV9LockYaml represents the structure of pnpm lockfiles for versions >= 9.0. // pnpmV9LockYaml represents the structure of pnpm lockfiles for versions >= 9.0.
@ -117,7 +120,7 @@ func (p *pnpmV6LockYaml) Parse(version float64, data []byte) ([]pnpmPackage, err
dependencies[depName] = normalizedVersion dependencies[depName] = normalizedVersion
} }
packages[pkgKey] = pnpmPackage{Name: name, Version: ver, Integrity: integrity, Dependencies: dependencies} packages[pkgKey] = pnpmPackage{Name: name, Version: ver, Integrity: integrity, Dependencies: dependencies, Dev: pkgInfo.Dev}
} }
return toSortedSlice(packages), nil return toSortedSlice(packages), nil
@ -141,7 +144,7 @@ func (p *pnpmV9LockYaml) Parse(_ float64, data []byte) ([]pnpmPackage, error) {
continue continue
} }
pkgKey := name + "@" + ver pkgKey := name + "@" + ver
packages[pkgKey] = pnpmPackage{Name: name, Version: ver, Integrity: entry.Resolution["integrity"]} packages[pkgKey] = pnpmPackage{Name: name, Version: ver, Integrity: entry.Resolution["integrity"], Dev: entry.Dev}
} }
for key, snapshotInfo := range p.Snapshots { for key, snapshotInfo := range p.Snapshots {
@ -199,9 +202,12 @@ func (a genericPnpmLockAdapter) parsePnpmLock(ctx context.Context, resolver file
return nil, nil, fmt.Errorf("failed to parse pnpm-lock.yaml file: %w", err) return nil, nil, fmt.Errorf("failed to parse pnpm-lock.yaml file: %w", err)
} }
packages := make([]pkg.Package, len(pnpmPkgs)) packages := make([]pkg.Package, 0, len(pnpmPkgs))
for i, p := range pnpmPkgs { for _, p := range pnpmPkgs {
packages[i] = newPnpmPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Dependencies) if p.Dev && !a.cfg.IncludeDevDependencies {
continue
}
packages = append(packages, newPnpmPackage(ctx, a.cfg, resolver, reader.Location, p.Name, p.Version, p.Integrity, p.Dependencies))
} }
return packages, dependency.Resolve(pnpmLockDependencySpecifier, packages), unknown.IfEmptyf(packages, "unable to determine packages") return packages, dependency.Resolve(pnpmLockDependencySpecifier, packages), unknown.IfEmptyf(packages, "unable to determine packages")

View File

@ -62,7 +62,47 @@ func TestParsePnpmLock(t *testing.T) {
}, },
} }
adapter := newGenericPnpmLockAdapter(CatalogerConfig{}) adapter := newGenericPnpmLockAdapter(CatalogerConfig{IncludeDevDependencies: true})
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expectedPkgs, expectedRelationships)
}
func TestParsePnpmLock_ExcludeDevDependencies(t *testing.T) {
var expectedRelationships []artifact.Relationship
fixture := "test-fixtures/pnpm/pnpm-lock.yaml"
locationSet := file.NewLocationSet(file.NewLocation(fixture))
expectedPkgs := []pkg.Package{
{
Name: "nanoid",
Version: "3.3.4",
PURL: "pkg:npm/nanoid@3.3.4",
Locations: locationSet,
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Metadata: pkg.PnpmLockEntry{Resolution: pkg.PnpmLockResolution{}},
},
{
Name: "picocolors",
Version: "1.0.0",
PURL: "pkg:npm/picocolors@1.0.0",
Locations: locationSet,
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Metadata: pkg.PnpmLockEntry{Resolution: pkg.PnpmLockResolution{}},
},
{
Name: "source-map-js",
Version: "1.0.2",
PURL: "pkg:npm/source-map-js@1.0.2",
Locations: locationSet,
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Metadata: pkg.PnpmLockEntry{Resolution: pkg.PnpmLockResolution{}},
},
}
adapter := newGenericPnpmLockAdapter(CatalogerConfig{IncludeDevDependencies: false})
pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expectedPkgs, expectedRelationships) pkgtest.TestFileParser(t, fixture, adapter.parsePnpmLock, expectedPkgs, expectedRelationships)
} }