diff --git a/mapper.go b/mapper.go index 139b2df..e8778ee 100644 --- a/mapper.go +++ b/mapper.go @@ -262,8 +262,7 @@ func (r *Registry) RegisterDefaults() *Registry { RegisterKind(reflect.Float32, floatDecoder(32)). RegisterKind(reflect.Float64, floatDecoder(64)). RegisterKind(reflect.String, MapperFunc(func(ctx *DecodeContext, target reflect.Value) error { - err := ctx.Scan.PopValueInto("string", target.Addr().Interface()) - return err + return ctx.Scan.PopValueInto("string", target.Addr().Interface()) })). RegisterKind(reflect.Bool, boolMapper{}). RegisterKind(reflect.Slice, sliceDecoder(r)). @@ -450,7 +449,7 @@ func mapDecoder(r *Registry) MapperFunc { } switch v := t.Value.(type) { case string: - childScanner = Scan(SplitEscaped(v, sep)...) + childScanner = ScanAsType(t.Type, SplitEscaped(v, sep)...) case []map[string]interface{}: for _, m := range v { @@ -492,14 +491,14 @@ func mapDecoder(r *Registry) MapperFunc { keyTypeName, valueTypeName = parts[0], parts[1] } - keyScanner := Scan(key) + keyScanner := ScanAsType(FlagValueToken, key) keyDecoder := r.ForNamedType(keyTypeName, el.Key()) keyValue := reflect.New(el.Key()).Elem() if err := keyDecoder.Decode(ctx.WithScanner(keyScanner), keyValue); err != nil { return fmt.Errorf("invalid map key %q", key) } - valueScanner := Scan(value) + valueScanner := ScanAsType(FlagValueToken, value) valueDecoder := r.ForNamedType(valueTypeName, el.Elem()) valueValue := reflect.New(el.Elem()).Elem() if err := valueDecoder.Decode(ctx.WithScanner(valueScanner), valueValue); err != nil { @@ -525,7 +524,7 @@ func sliceDecoder(r *Registry) MapperFunc { } switch v := t.Value.(type) { case string: - childScanner = Scan(SplitEscaped(v, sep)...) + childScanner = ScanAsType(t.Type, SplitEscaped(v, sep)...) case []interface{}: return jsonTranscode(v, target.Addr().Interface()) diff --git a/mapper_test.go b/mapper_test.go index 8263b0d..fdd7c8e 100644 --- a/mapper_test.go +++ b/mapper_test.go @@ -495,3 +495,21 @@ func (t testMapperVarsContributor) Decode(ctx *kong.DecodeContext, target reflec target.SetString("hi") return nil } + +func TestValuesThatLookLikeFlags(t *testing.T) { + var cli struct { + Slice []string + Map map[string]string + } + k := mustNew(t, &cli) + _, err := k.Parse([]string{"--slice", "-foo"}) + require.Error(t, err) + _, err = k.Parse([]string{"--map", "-foo=-bar"}) + require.Error(t, err) + _, err = k.Parse([]string{"--slice=-foo", "--slice=-bar"}) + require.NoError(t, err) + require.Equal(t, []string{"-foo", "-bar"}, cli.Slice) + _, err = k.Parse([]string{"--map=-foo=-bar"}) + require.NoError(t, err) + require.Equal(t, map[string]string{"-foo": "-bar"}, cli.Map) +} diff --git a/scanner.go b/scanner.go index 11b78c3..1766c4b 100644 --- a/scanner.go +++ b/scanner.go @@ -114,15 +114,20 @@ type Scanner struct { args []Token } -// Scan creates a new Scanner from args with untyped tokens. -func Scan(args ...string) *Scanner { +// ScanAsType creates a new Scanner from args with the given type. +func ScanAsType(ttype TokenType, args ...string) *Scanner { s := &Scanner{} for _, arg := range args { - s.args = append(s.args, Token{Value: arg}) + s.args = append(s.args, Token{Value: arg, Type: ttype}) } return s } +// Scan creates a new Scanner from args with untyped tokens. +func Scan(args ...string) *Scanner { + return ScanAsType(UntypedToken, args...) +} + // ScanFromTokens creates a new Scanner from a slice of tokens. func ScanFromTokens(tokens ...Token) *Scanner { return &Scanner{args: tokens}