diff --git a/pkg/commands/dependency.go b/pkg/commands/dependency.go index 6e71ee7..81a440d 100644 --- a/pkg/commands/dependency.go +++ b/pkg/commands/dependency.go @@ -6,13 +6,14 @@ import ( ) type Dependency struct { - Name string - Version string - LinkPath string - Present bool - PackageConfig *PackageConfig - Path string - Kind string + Name string + Constraint string + LinkPath string + Present bool + PackageConfig *PackageConfig + Path string + Kind string + ParentPackagePath string } func (d *Dependency) Linked() bool { @@ -26,3 +27,24 @@ func (d *Dependency) ConfigPath() string { func (d *Dependency) ID() string { return fmt.Sprintf("dep:%s|kind:%s", d.Path, d.Kind) } + +func KindKeyMap() map[string]string { + return map[string]string{ + "prod": "dependencies", + "dev": "devDependencies", + "optional": "optionalDependencies", + "peer": "peerDependencies", + } +} + +func KindFlagMap() map[string]string { + return map[string]string{ + "prod": "--save-prod", + "dev": "--save-dev", + "optional": "--save-optional", + } +} + +func (d *Dependency) kindKey() string { + return KindKeyMap()[d.Kind] +} diff --git a/pkg/commands/npm_manager.go b/pkg/commands/npm_manager.go index 7ddcbac..90991df 100644 --- a/pkg/commands/npm_manager.go +++ b/pkg/commands/npm_manager.go @@ -1,6 +1,7 @@ package commands import ( + "fmt" "io/ioutil" "os" "path/filepath" @@ -126,6 +127,7 @@ func (m *NpmManager) GetDeps(currentPkg *Package) ([]*Dependency, error) { for _, dep := range deps { depPath := filepath.Join(currentPkg.Path, "node_modules", dep.Name) dep.Path = depPath + dep.ParentPackagePath = currentPkg.Path fileInfo, err := os.Lstat(depPath) if err != nil { // must not be present in node modules @@ -174,3 +176,17 @@ func (m *NpmManager) RemoveScript(scriptName string, packageJsonPath string) err return ioutil.WriteFile(packageJsonPath, updatedConfig, 0644) } + +func (m *NpmManager) EditDepConstraint(dep *Dependency, packageJsonPath string, constraint string) error { + config, err := ioutil.ReadFile(packageJsonPath) + if err != nil { + return err + } + + updatedConfig, err := jsonparser.Set(config, []byte(fmt.Sprintf("\"%s\"", constraint)), dep.kindKey(), dep.Name) + if err != nil { + return err + } + + return ioutil.WriteFile(packageJsonPath, updatedConfig, 0644) +} diff --git a/pkg/commands/package.go b/pkg/commands/package.go index 2f30918..7aca089 100644 --- a/pkg/commands/package.go +++ b/pkg/commands/package.go @@ -114,9 +114,9 @@ func (p *Package) SortedDependencies() []*Dependency { depsForKind := make([]*Dependency, 0, len(mapping.depMap)) for name, constraint := range mapping.depMap { depsForKind = append(depsForKind, &Dependency{ - Name: name, - Version: constraint, - Kind: mapping.kind, + Name: name, + Constraint: constraint, + Kind: mapping.kind, }) } sort.Slice(depsForKind, func(i, j int) bool { return strings.Compare(depsForKind[i].Name, depsForKind[j].Name) < 0 }) diff --git a/pkg/gui/dependencies_panel.go b/pkg/gui/dependencies_panel.go index b3666c7..fce1f65 100644 --- a/pkg/gui/dependencies_panel.go +++ b/pkg/gui/dependencies_panel.go @@ -2,6 +2,7 @@ package gui import ( "fmt" + "path/filepath" "github.com/fatih/color" "github.com/go-errors/errors" @@ -133,29 +134,18 @@ func (gui *Gui) wrappedDependencyHandler(f func(*commands.Dependency) error) fun } func (gui *Gui) handleChangeDepType(dep *commands.Dependency) error { - installProd := fmt.Sprintf("npm install --save-prod %s", dep.Name) - installDev := fmt.Sprintf("npm install --save-dev %s", dep.Name) - installOptional := fmt.Sprintf("npm install --save-optional %s", dep.Name) - - menuItems := []*menuItem{ - { - displayStrings: []string{"dependencies", utils.ColoredString(installProd, color.FgYellow)}, - onPress: func() error { - return gui.newMainCommand(installProd, dep.ID()) - }, - }, - { - displayStrings: []string{"devDependencies", utils.ColoredString(installDev, color.FgYellow)}, - onPress: func() error { - return gui.newMainCommand(installDev, dep.ID()) - }, - }, - { - displayStrings: []string{"optionalDependencies", utils.ColoredString(installOptional, color.FgYellow)}, + kindKeyMap := commands.KindKeyMap() + kindFlagMap := commands.KindFlagMap() + menuItems := make([]*menuItem, 0, len(commands.KindKeyMap())) + for kind := range kindFlagMap { + kind := kind + cmdStr := fmt.Sprintf("npm install %s %s", kindFlagMap[kind], dep.Name) + menuItems = append(menuItems, &menuItem{ + displayStrings: []string{kindKeyMap[kind], utils.ColoredString(cmdStr, color.FgYellow)}, onPress: func() error { - return gui.newMainCommand(installOptional, dep.ID()) + return gui.newMainCommand(cmdStr, dep.ID()) }, - }, + }) } return gui.createMenu("Change dependency type", menuItems, createMenuOptions{showCancel: true}) @@ -171,30 +161,27 @@ func (gui *Gui) handleAddDependency(dep *commands.Dependency) error { }) } - installProd := "npm install --save-prod" - installDev := "npm install --save-dev" - installOptional := "npm install --save-optional" - - menuItems := []*menuItem{ - { - displayStrings: []string{"dependencies", utils.ColoredString(installProd, color.FgYellow)}, - onPress: func() error { - return prompt(installProd) - }, - }, - { - displayStrings: []string{"devDependencies", utils.ColoredString(installDev, color.FgYellow)}, - onPress: func() error { - return prompt(installDev) - }, - }, - { - displayStrings: []string{"optionalDependencies", utils.ColoredString(installOptional, color.FgYellow)}, + kindKeyMap := commands.KindKeyMap() + kindFlagMap := commands.KindFlagMap() + menuItems := make([]*menuItem, 0, len(commands.KindKeyMap())) + for kind := range kindFlagMap { + kind := kind + cmdStr := fmt.Sprintf("npm install %s", kindFlagMap[kind]) + menuItems = append(menuItems, &menuItem{ + displayStrings: []string{kindKeyMap[kind], utils.ColoredString(cmdStr, color.FgYellow)}, onPress: func() error { - return prompt(installOptional) + return prompt(cmdStr) }, - }, + }) } return gui.createMenu("Install dependency to:", menuItems, createMenuOptions{showCancel: true}) } + +func (gui *Gui) handleEditDepConstraint(dep *commands.Dependency) error { + return gui.createPromptPanel(gui.getDepsView(), "Edit constraint", dep.Constraint, func(input string) error { + + packageConfigPath := filepath.Join(dep.ParentPackagePath, "package.json") + return gui.NpmManager.EditDepConstraint(dep, packageConfigPath, input) + }) +} diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 46c31d2..70365dd 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -469,6 +469,12 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Handler: gui.wrappedDependencyHandler(gui.handleAddDependency), Description: fmt.Sprintf("%s new dependency", utils.ColoredString("`npm install`", color.FgYellow)), }, + { + ViewName: "deps", + Key: gui.getKey("universal.edit"), + Handler: gui.wrappedDependencyHandler(gui.handleEditDepConstraint), + Description: "edit dependency constraint", + }, } for _, viewName := range []string{"status", "packages", "deps", "scripts", "menu"} { diff --git a/pkg/gui/presentation/dependencies.go b/pkg/gui/presentation/dependencies.go index 7f7f446..ec605d3 100644 --- a/pkg/gui/presentation/dependencies.go +++ b/pkg/gui/presentation/dependencies.go @@ -27,7 +27,7 @@ func getDepDisplayStrings(d *commands.Dependency, commandView *commands.CommandV if d.Linked() { localVersionCol = utils.ColoredString("linked: "+d.LinkPath, color.FgCyan) } else if d.PackageConfig != nil { - status, ok := semverStatus(d.PackageConfig.Version, d.Version) + status, ok := semverStatus(d.PackageConfig.Version, d.Constraint) if ok { localVersionCol = utils.ColoredString(d.PackageConfig.Version, color.FgGreen) } else { @@ -44,7 +44,7 @@ func getDepDisplayStrings(d *commands.Dependency, commandView *commands.CommandV "optional": theme.DefaultTextColor, } - return []string{commandView.Status(), d.Name, utils.ColoredString(d.Kind, kindColorMap[d.Kind]), utils.ColoredString(d.Version, color.FgMagenta), localVersionCol} + return []string{commandView.Status(), d.Name, utils.ColoredString(d.Kind, kindColorMap[d.Kind]), utils.ColoredString(d.Constraint, color.FgMagenta), localVersionCol} } func statusMap() map[int]string {