From aa6cb95149b650d07de76176d652b7280c86db06 Mon Sep 17 00:00:00 2001 From: Alex Flint Date: Sun, 31 Jan 2021 18:29:22 -0800 Subject: [PATCH] skip unexported fields --- parse.go | 2 +- parse_test.go | 9 +++++++++ reflect.go | 8 ++++++++ reflect_test.go | 7 +++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/parse.go b/parse.go index 8fdbd9d..0c65397 100644 --- a/parse.go +++ b/parse.go @@ -263,7 +263,7 @@ func cmdFromStruct(name string, dest path, t reflect.Type) (*command, error) { walkFields(t, func(field reflect.StructField, t reflect.Type) bool { // Check for the ignore switch in the tag tag := field.Tag.Get("arg") - if tag == "-" { + if tag == "-" || !isExported(field.Name) { return false } diff --git a/parse_test.go b/parse_test.go index ad668a9..a0334c7 100644 --- a/parse_test.go +++ b/parse_test.go @@ -1213,3 +1213,12 @@ func TestDefaultValuesNotAllowedWithSlice(t *testing.T) { err := parse("", &args) assert.EqualError(t, err, ".A: default values are not supported for slice fields") } + +func TestUnexportedFieldsSkipped(t *testing.T) { + var args struct { + unexported struct{} + } + + _, err := NewParser(Config{}, &args) + require.NoError(t, err) +} diff --git a/reflect.go b/reflect.go index e113583..f1e8e8d 100644 --- a/reflect.go +++ b/reflect.go @@ -3,6 +3,8 @@ package arg import ( "encoding" "reflect" + "unicode" + "unicode/utf8" scalar "github.com/alexflint/go-scalar" ) @@ -60,3 +62,9 @@ func isBoolean(t reflect.Type) bool { return false } } + +// isExported returns true if the struct field name is exported +func isExported(field string) bool { + r, _ := utf8.DecodeRuneInString(field) // returns RuneError for empty string or invalid UTF8 + return unicode.IsLetter(r) && unicode.IsUpper(r) +} diff --git a/reflect_test.go b/reflect_test.go index 47e68b5..07b459c 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -53,3 +53,10 @@ func TestCanParseTextUnmarshaler(t *testing.T) { assertCanParse(t, reflect.TypeOf(su), true, false, true) assertCanParse(t, reflect.TypeOf(&su), true, false, true) } + +func TestIsExported(t *testing.T) { + assert.True(t, isExported("Exported")) + assert.False(t, isExported("notExported")) + assert.False(t, isExported("")) + assert.False(t, isExported(string([]byte{255}))) +}