diff --git a/tpl/debug/debug.go b/tpl/debug/debug.go index 04fb7156547..8131873a902 100644 --- a/tpl/debug/debug.go +++ b/tpl/debug/debug.go @@ -15,6 +15,9 @@ package debug import ( + "reflect" + "sort" + "github.com/sanity-io/litter" "github.com/gohugoio/hugo/deps" @@ -38,3 +41,51 @@ type Namespace struct { func (ns *Namespace) Dump(val any) string { return litter.Sdump(val) } + +// List returns the fields and methods of the struct/pointer or keys of the map. +func (ns *Namespace) List(val interface{}) []string { + values := make([]string, 0) + + v := reflect.ValueOf(val) + + // If the type is struct + if v.Kind() == reflect.Struct { + for i := 0; i < v.NumField(); i++ { + if v.Type().Field(i).IsExported() { + values = append(values, v.Type().Field(i).Name) + } + } + + for i := 0; i < v.NumMethod(); i++ { + if v.Type().Method(i).IsExported() { + values = append(values, v.Type().Method(i).Name) + } + } + } + + // If the type is pointer + if v.Kind() == reflect.Ptr { + for i := 0; i < reflect.Indirect(v).NumField(); i++ { + if v.Elem().Type().Field(i).IsExported() { + values = append(values, v.Elem().Type().Field(i).Name) + } + } + + for i := 0; i < v.NumMethod(); i++ { + if v.Type().Method(i).IsExported() { + values = append(values, v.Type().Method(i).Name) + } + } + } + + // If the type is map + if v.Kind() == reflect.Map { + iter := v.MapRange() + for iter.Next() { + values = append(values, iter.Key().String()) + } + } + + sort.Strings(values) + return values +} diff --git a/tpl/debug/debug_test.go b/tpl/debug/debug_test.go new file mode 100644 index 00000000000..3a8a7dac368 --- /dev/null +++ b/tpl/debug/debug_test.go @@ -0,0 +1,67 @@ +package debug + +import ( + "testing" + + qt "github.com/frankban/quicktest" +) + +type User struct { + Name string + Phone string + city string +} + +func (u User) GetName() string { + return u.Name +} + +func (u User) GetPhone() string { + return u.Phone +} + +func (u *User) getCity() string { + return u.city +} + +func (u *User) GetPhoneAndCity() string { + return u.Phone + u.city +} + +func TestList(t *testing.T) { + user := User{"a name", "9876543210", "SF"} + ns := Namespace{} + + t.Run("struct", func(t *testing.T) { + c := qt.New(t) + result := ns.List(user) + c.Assert(len(result), qt.Equals, 4) + c.Assert(result[0], qt.Equals, "GetName") + c.Assert(result[1], qt.Equals, "GetPhone") + c.Assert(result[2], qt.Equals, "Name") + c.Assert(result[3], qt.Equals, "Phone") + }) + + t.Run("pointer", func(t *testing.T) { + c := qt.New(t) + result := ns.List(&user) + c.Assert(len(result), qt.Equals, 5) + c.Assert(result[0], qt.Equals, "GetName") + c.Assert(result[1], qt.Equals, "GetPhone") + c.Assert(result[2], qt.Equals, "GetPhoneAndCity") + c.Assert(result[3], qt.Equals, "Name") + c.Assert(result[4], qt.Equals, "Phone") + }) + + t.Run("map", func(t *testing.T) { + c := qt.New(t) + mapTestCase := map[string]string{ + "name": "a name", + "phone": "a phone", + } + result := ns.List(mapTestCase) + c.Assert(result[0], qt.Equals, "name") + c.Assert(result[1], qt.Equals, "phone") + }) + +}