Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a bunch of positional argument validators #23

Merged
merged 1 commit into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ tasks:
msg: golines not installed, see https://github.com/segmentio/golines
cmds:
- go fmt ./...
- golines . --chain-split-dots --ignore-generated --write-output
- golines . --ignore-generated --write-output

test:
desc: Run the test suite
Expand Down
107 changes: 106 additions & 1 deletion command/args.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package command

import "fmt"
import (
"fmt"
"slices"
)

// AnyArgs is a positional argument validator that allows any arbitrary args,
// it never returns an error.
Expand All @@ -18,3 +21,105 @@ func NoArgs(cmd *Command, args []string) error {
}
return nil
}

// MinArgs is a positional argument validator that requires at least n arguments.
func MinArgs(n int) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
if len(args) < n {
return fmt.Errorf(
"command %s requires at least %d arguments, but got %d: %v",
cmd.name,
n,
len(args),
args,
)
}
return nil
}
}

// MaxArgs is a positional argument validator that returns an error if there are more than n arguments.
func MaxArgs(n int) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
if len(args) > n {
return fmt.Errorf(
"command %s has a limit of %d arguments, but got %d: %v",
cmd.name,
n,
len(args),
args,
)
}
return nil
}
}

// ExactArgs is a positional argument validator that allows exactly n args, any more
// or less will return an error.
func ExactArgs(n int) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
if len(args) != n {
return fmt.Errorf(
"command %s requires exactly %d arguments, but got %d: %v",
cmd.name,
n,
len(args),
args,
)
}
return nil
}
}

// BetweenArgs is a positional argument validator that allows between min and max arguments (inclusive),
// any outside that range will return an error.
func BetweenArgs(min, max int) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
nArgs := len(args)
if nArgs < min || nArgs > max {
return fmt.Errorf(
"command %s requires between %d and %d arguments, but got %d: %v",
cmd.name,
min,
max,
nArgs,
args,
)
}
return nil
}
}

// ValidArgs is a positional argument validator that only allows arguments that are contained in
// the valid slice. If any non-valid arguments are seen, an error will be returned.
func ValidArgs(valid []string) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
for _, arg := range args {
if !slices.Contains(valid, arg) {
return fmt.Errorf(
"command %s got an invalid argument %s, expected one of %v",
cmd.name,
arg,
valid,
)
}
}
return nil
}
}

// Combine allows multiple positional argument validators to be composed together.
//
// The first validator to fail will be the one that returns the error.
func Combine(
validators ...func(cmd *Command, args []string) error,
) func(cmd *Command, args []string) error {
return func(cmd *Command, args []string) error {
for _, validator := range validators {
if err := validator(cmd, args); err != nil {
return err
}
}
return nil
}
}
Loading
Loading