fix: overly enthusiastic validation of tags
This commit is contained in:
@@ -167,14 +167,13 @@ MAIN:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan through argument positionals to ensure optional is never before a required.
|
// Scan through argument positionals to ensure optional is never before a required.
|
||||||
last := true
|
var last *Value
|
||||||
for i, p := range node.Positional {
|
for i, curr := range node.Positional {
|
||||||
if !last && p.Required {
|
if last != nil && !last.Required && curr.Required {
|
||||||
return nil, fmt.Errorf("argument %q can not be required after an optional", p.Name)
|
return nil, fmt.Errorf("%s: required %q can not come after optional %q", node.FullPath(), curr.Name, last.Name)
|
||||||
}
|
}
|
||||||
|
last = curr
|
||||||
last = p.Required
|
curr.Position = i
|
||||||
p.Position = i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node, nil
|
return node, nil
|
||||||
|
|||||||
@@ -1382,3 +1382,19 @@ func TestOptionReturnsErr(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Equal(t, "option returned err", err.Error())
|
require.Equal(t, "option returned err", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnumValidation(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Enum string `arg:"" enum:"one,two"`
|
||||||
|
}
|
||||||
|
_, err := kong.New(&cli)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnumValidationSlice(t *testing.T) {
|
||||||
|
var cli struct {
|
||||||
|
Enum []string `arg:"" enum:"one,two"`
|
||||||
|
}
|
||||||
|
_, err := kong.New(&cli)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func parseTagString(s string) (*Tag, error) {
|
|||||||
t := &Tag{
|
t := &Tag{
|
||||||
items: items,
|
items: items,
|
||||||
}
|
}
|
||||||
err = hydrateTag(t, "", false)
|
err = hydrateTag(t, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: %s", s, err)
|
return nil, fmt.Errorf("%s: %s", s, err)
|
||||||
}
|
}
|
||||||
@@ -158,14 +158,20 @@ func parseTag(parent reflect.Value, ft reflect.StructField) (*Tag, error) {
|
|||||||
t := &Tag{
|
t := &Tag{
|
||||||
items: items,
|
items: items,
|
||||||
}
|
}
|
||||||
err = hydrateTag(t, ft.Type.Name(), ft.Type.Kind() == reflect.Bool)
|
err = hydrateTag(t, ft.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, failField(parent, ft, "%s", err)
|
return nil, failField(parent, ft, "%s", err)
|
||||||
}
|
}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hydrateTag(t *Tag, typeName string, isBool bool) error {
|
func hydrateTag(t *Tag, typ reflect.Type) error { // nolint: gocyclo
|
||||||
|
var typeName string
|
||||||
|
var isBool bool
|
||||||
|
if typ != nil {
|
||||||
|
typeName = typ.Name()
|
||||||
|
isBool = typ.Kind() == reflect.Bool
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
t.Cmd = t.Has("cmd")
|
t.Cmd = t.Has("cmd")
|
||||||
t.Arg = t.Has("arg")
|
t.Arg = t.Has("arg")
|
||||||
@@ -220,7 +226,8 @@ func hydrateTag(t *Tag, typeName string, isBool bool) error {
|
|||||||
}
|
}
|
||||||
t.PlaceHolder = t.Get("placeholder")
|
t.PlaceHolder = t.Get("placeholder")
|
||||||
t.Enum = t.Get("enum")
|
t.Enum = t.Get("enum")
|
||||||
if t.Enum != "" && !(t.Required || t.Default != "") {
|
scalarType := (typ == nil || !(typ.Kind() == reflect.Slice || typ.Kind() == reflect.Map))
|
||||||
|
if t.Enum != "" && !(t.Required || t.Default != "") && scalarType {
|
||||||
return fmt.Errorf("enum value is only valid if it is either required or has a valid default value")
|
return fmt.Errorf("enum value is only valid if it is either required or has a valid default value")
|
||||||
}
|
}
|
||||||
passthrough := t.Has("passthrough")
|
passthrough := t.Has("passthrough")
|
||||||
|
|||||||
Reference in New Issue
Block a user