@@ -663,8 +663,7 @@ func main() {
|
|||||||
## Validation
|
## Validation
|
||||||
|
|
||||||
Kong does validation on the structure of a command-line, but also supports
|
Kong does validation on the structure of a command-line, but also supports
|
||||||
extensible validation. Any node in the tree may implement the following
|
extensible validation. Any node in the tree may implement either of the following interfaces:
|
||||||
interface:
|
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Validatable interface {
|
type Validatable interface {
|
||||||
@@ -672,6 +671,12 @@ type Validatable interface {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Validatable interface {
|
||||||
|
Validate(kctx *kong.Context) error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
If one of these nodes is in the active command-line it will be called during
|
If one of these nodes is in the active command-line it will be called during
|
||||||
normal validation.
|
normal validation.
|
||||||
|
|
||||||
|
|||||||
+13
-2
@@ -208,7 +208,7 @@ func (c *Context) Validate() error { //nolint: gocyclo
|
|||||||
desc = node.Path()
|
desc = node.Path()
|
||||||
}
|
}
|
||||||
if validate := isValidatable(value); validate != nil {
|
if validate := isValidatable(value); validate != nil {
|
||||||
if err := validate.Validate(); err != nil {
|
if err := validate.Validate(c); err != nil {
|
||||||
if desc != "" {
|
if desc != "" {
|
||||||
return fmt.Errorf("%s: %w", desc, err)
|
return fmt.Errorf("%s: %w", desc, err)
|
||||||
}
|
}
|
||||||
@@ -1094,12 +1094,23 @@ func findPotentialCandidates(needle string, haystack []string, format string, ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
type validatable interface{ Validate() error }
|
type validatable interface{ Validate() error }
|
||||||
|
type extendedValidatable interface {
|
||||||
|
Validate(kctx *Context) error
|
||||||
|
}
|
||||||
|
|
||||||
func isValidatable(v reflect.Value) validatable {
|
// Proxy a validatable function to the extendedValidatable interface
|
||||||
|
type validatableFunc func() error
|
||||||
|
|
||||||
|
func (f validatableFunc) Validate(kctx *Context) error { return f() }
|
||||||
|
|
||||||
|
func isValidatable(v reflect.Value) extendedValidatable {
|
||||||
if !v.IsValid() || (v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map) && v.IsNil() {
|
if !v.IsValid() || (v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map) && v.IsNil() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if validate, ok := v.Interface().(validatable); ok {
|
if validate, ok := v.Interface().(validatable); ok {
|
||||||
|
return validatableFunc(validate.Validate)
|
||||||
|
}
|
||||||
|
if validate, ok := v.Interface().(extendedValidatable); ok {
|
||||||
return validate
|
return validate
|
||||||
}
|
}
|
||||||
if v.CanAddr() {
|
if v.CanAddr() {
|
||||||
|
|||||||
@@ -1466,6 +1466,19 @@ func TestValidateArg(t *testing.T) {
|
|||||||
assert.EqualError(t, err, "<arg>: flag error")
|
assert.EqualError(t, err, "<arg>: flag error")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type extendedValidateFlag string
|
||||||
|
|
||||||
|
func (v *extendedValidateFlag) Validate(kctx *kong.Context) error { return errors.New("flag error") }
|
||||||
|
|
||||||
|
func TestExtendedValidateFlag(t *testing.T) {
|
||||||
|
cli := struct {
|
||||||
|
Flag extendedValidateFlag
|
||||||
|
}{}
|
||||||
|
p := mustNew(t, &cli)
|
||||||
|
_, err := p.Parse([]string{"--flag=one"})
|
||||||
|
assert.EqualError(t, err, "--flag: flag error")
|
||||||
|
}
|
||||||
|
|
||||||
func TestPointers(t *testing.T) {
|
func TestPointers(t *testing.T) {
|
||||||
cli := struct {
|
cli := struct {
|
||||||
Mapped *mappedValue
|
Mapped *mappedValue
|
||||||
|
|||||||
Reference in New Issue
Block a user