fix(npm): handle multiple packages and flag parsing correctly (#17)

* fix(npm): handle multiple packages and flag parsing correctly

- Fixes issue where only the first package was scanned; now all packages in install command are parsed and processed.
- Correctly separates flags (e.g., --save-dev) from package names to avoid treating them as packages.
- Applies same fixes to both npm and pnpm flows.
- Updated wrapper to scan all packages before installing, maintaining original CLI behavior.

* refactor: fixed the registry type

* feat: continue installing other packages if one is denied

* Update pkg/wrapper/npm_base.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* fix(wrapper): exit gracefully for user-rejected packages

* fix: remove env validation

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Sahil Bansal
2025-05-12 09:23:08 +05:30
committed by GitHub
co-authored by Copilot
parent f7855e99a2
commit 8b46964c7a
6 changed files with 146 additions and 73 deletions
+64
View File
@@ -0,0 +1,64 @@
package utils
import (
"fmt"
"strings"
)
// ParseNpmInstallArgs parses npm install command arguments and returns
// separated flags and packages. It expects args to include the full command
// including "npm" and "install" at the start
func ParseNpmInstallArgs(args []string) ([]string, []string) {
var flags []string
var packages []string
for _, arg := range args {
if strings.HasPrefix(arg, "-") {
flags = append(flags, arg)
} else {
packages = append(packages, arg)
}
}
return flags, packages
}
func CleanVersion(version string) string {
version = strings.TrimPrefix(version, "^")
version = strings.TrimPrefix(version, "~")
if version == "*" {
return "latest"
}
return version
}
func ParsePackageInfo(input string) (packageName, version string, err error) {
if input == "" {
return "", "", fmt.Errorf("package info cannot be empty")
}
input = strings.TrimSpace(input)
if strings.HasPrefix(input, "@") {
lastAtIndex := strings.LastIndex(input, "@")
if lastAtIndex > 0 {
packageName = strings.TrimSpace(input[:lastAtIndex])
version = strings.TrimSpace(input[lastAtIndex+1:])
return packageName, version, nil
}
// If no version specifier, return the whole input as package name
return strings.TrimSpace(input), "", nil
}
pkg := strings.Split(input, "@")
if len(pkg) == 2 {
packageName = strings.TrimSpace(pkg[0])
version = strings.TrimSpace(pkg[1])
return packageName, version, nil
}
if len(pkg) == 1 {
packageName = strings.TrimSpace(pkg[0])
return packageName, "", nil
}
return "", "", fmt.Errorf("invalid format: expected 'package' OR 'package@version', got '%s'", input)
}
-46
View File
@@ -1,51 +1,5 @@
package utils
import (
"fmt"
"strings"
)
func CleanVersion(version string) string {
version = strings.TrimPrefix(version, "^")
version = strings.TrimPrefix(version, "~")
if version == "*" {
return "latest"
}
return version
}
func ParsePackageInfo(input string) (packageName, version string, err error) {
if input == "" {
return "", "", fmt.Errorf("package info cannot be empty")
}
input = strings.TrimSpace(input)
if strings.HasPrefix(input, "@") {
lastAtIndex := strings.LastIndex(input, "@")
if lastAtIndex > 0 {
packageName = strings.TrimSpace(input[:lastAtIndex])
version = strings.TrimSpace(input[lastAtIndex+1:])
return packageName, version, nil
}
// If no version specifier, return the whole input as package name
return strings.TrimSpace(input), "", nil
}
pkg := strings.Split(input, "@")
if len(pkg) == 2 {
packageName = strings.TrimSpace(pkg[0])
version = strings.TrimSpace(pkg[1])
return packageName, version, nil
}
if len(pkg) == 1 {
packageName = strings.TrimSpace(pkg[0])
return packageName, "", nil
}
return "", "", fmt.Errorf("invalid format: expected 'package' OR 'package@version', got '%s'", input)
}
func IsInstallCommand(pkgManager, cmd string) bool {
validActions := map[string]map[string]bool{
"npm": {