diff --git a/viper.go b/viper.go index 4ed2d40..d45b82c 100644 --- a/viper.go +++ b/viper.go @@ -30,6 +30,7 @@ import ( "strings" "time" + "github.com/deckarep/golang-set" "github.com/fsnotify/fsnotify" "github.com/mitchellh/mapstructure" "github.com/spf13/afero" @@ -1336,6 +1337,32 @@ func (v *Viper) AllKeys() []string { return a } +// Get the set of all top level keys. +func TopLevelKeys() []string { return v.TopLevelKeys() } +func (v *Viper) TopLevelKeys() []string { + s := mapset.NewSetFromSlice(v.getMapKeys(castMapStringToMapInterface(v.aliases))) + s = s.Union(mapset.NewSetFromSlice(v.getMapKeys(v.override))) + s = s.Union(mapset.NewSetFromSlice(v.getMapKeys(castMapFlagToMapInterface(v.pflags)))) + s = s.Union(mapset.NewSetFromSlice(v.getMapKeys(castMapStringToMapInterface(v.env)))) + s = s.Union(mapset.NewSetFromSlice(v.getMapKeys(v.config))) + s = s.Union(mapset.NewSetFromSlice(v.getMapKeys(v.defaults))) + + // convert interface{} to string + keys := []string{} + for _, k := range s.ToSlice() { + keys = append(keys, k.(string)) + } + return keys +} + +func (v *Viper) getMapKeys(m map[string]interface{}) []interface{} { + keys := []interface{}{} + for key := range m { + keys = append(keys, key) + } + return keys +} + // flattenAndMergeMap recursively flattens the given map into a map[string]bool // of key paths (used as a set, easier to manipulate than a []string): // - each path is merged into a single key string, delimited with v.keyDelim (= ".")