Add support for yarn package manager (#72)

* Add support for yarn package manager

- Added yarn command handler in cmd/npm/yarn.go
- Added DefaultYarnPackageManagerConfig() in packagemanager/npm.go
- Added yarn dev flag support (--dev/-D) in ParseCommand()
- Added yarn analytics tracking in internal/analytics/event.go
- Registered yarn command in main.go
- Added yarn to alias setup in internal/alias/alias.go
- Added comprehensive test suite in packagemanager/yarn_test.go
- All tests passing (12 yarn tests + existing tests)

Resolves #30

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

* docs: update README with yarn package manager support

Updated documentation to reflect yarn support addition:
- Changed yarn status from '🚧 Planned' to ' Active' in package managers table
- Added 'pmg yarn add <package>' command example
- Added 'yarn add <package-name>' to command list
- Added 'yarn install # Uses yarn.lock' to lockfile examples

This documentation update corresponds to the yarn implementation in the previous commit.

Related to #30

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

* fix: address review feedback for yarn support

- Add support for bare 'yarn' command as manifest install
- Validate yarn install does not accept package names
- Add YarnExtractor for yarn.lock file support

Changes:
- packagemanager/npm.go: Added bare yarn command handling and validation
- packagemanager/yarn_test.go: Added test for bare yarn command
- extractor/ecosystems.go: Added Yarn PackageManagerName and extractor
- extractor/npm.go: Added YarnExtractor implementation
- go.mod, go.sum: Updated dependencies

Addresses review feedback from @Sahilb315
- Bare yarn command now triggers manifest install per docs
- yarn install <package> is now properly rejected
- yarn.lock extraction support added

Related to #30

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

* chore: tidy go.mod and go.sum to remove unused dependencies

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

* fix: add yarn.lock extractor mapping

- Add yarn.lock case in getExtractorForFile switch
- Import yarnlock extractor from osv-scalibr
- Enables lockfile parsing for manifest-based installations

Tested both package-based and manifest-based installations successfully.

Addresses review feedback from @Sahilb315

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

* test: add validation test for yarn install with package name

- Add test case to verify 'yarn install <package>' is rejected
- Ensures invalid syntax returns no install targets
- Confirms IsManifestInstall is false for invalid commands

Addresses review feedback from @Sahilb315

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>

---------

Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
This commit is contained in:
Shrvan Sudhakara
2025-11-05 13:49:19 +05:30
committed by GitHub
parent 12aaba8a05
commit 03bd697ae0
10 changed files with 329 additions and 50 deletions
+3
View File
@@ -12,6 +12,7 @@ import (
"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/bunlock"
"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagelockjson"
"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/pnpmlock"
"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/yarnlock"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/poetrylock"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/requirements"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/uvlock"
@@ -31,6 +32,8 @@ func getExtractorForFile(filename string) (filesystem.Extractor, error) {
return pnpmlock.New(), nil
case filename == "bun.lock":
return bunlock.New(), nil
case filename == "yarn.lock":
return yarnlock.New(), nil
case reqPattern.MatchString(filename):
return requirements.NewDefault(), nil
case filename == "uv.lock":
+2
View File
@@ -26,6 +26,7 @@ const (
Pnpm PackageManagerName = "pnpm"
Pip PackageManagerName = "pip"
Bun PackageManagerName = "bun"
Yarn PackageManagerName = "yarn"
Uv PackageManagerName = "uv"
Poetry PackageManagerName = "poetry"
)
@@ -41,6 +42,7 @@ func NewExtractorManager() *ExtractorManager {
Pnpm: &PnpmExtractor{},
Pip: &PipExtractor{},
Bun: &BunExtractor{},
Yarn: &YarnExtractor{},
Uv: &UvExtractor{},
Poetry: &PoetryExtractor{},
},
+18
View File
@@ -59,3 +59,21 @@ func (n *BunExtractor) GetPackageManager() PackageManagerName {
func (n *BunExtractor) Extract(lockfilePath, scanDir string) ([]*packagev1.PackageVersion, error) {
return parseLockfile(lockfilePath, scanDir, n.GetEcosystem())
}
type YarnExtractor struct{}
func (y *YarnExtractor) GetSupportedFiles() []string {
return []string{"yarn.lock"}
}
func (y *YarnExtractor) GetEcosystem() packagev1.Ecosystem {
return packagev1.Ecosystem_ECOSYSTEM_NPM
}
func (y *YarnExtractor) GetPackageManager() PackageManagerName {
return Yarn
}
func (y *YarnExtractor) Extract(lockfilePath, scanDir string) ([]*packagev1.PackageVersion, error) {
return parseLockfile(lockfilePath, scanDir, y.GetEcosystem())
}