diff --git a/compose_tree.go b/compose_tree.go index 19307a0..94726ba 100644 --- a/compose_tree.go +++ b/compose_tree.go @@ -19,6 +19,31 @@ func composeTree(value reflect.Value, prefix string) { } } + // Resolve Ptrs if any. + for { + if value.Kind() == reflect.Ptr { + value = value.Elem() + typeOf = value.Type() + } else { + break + } + } + + if value.Kind() != reflect.Struct { + f := &field{ + Name: typeOf.Name(), + EnvVar: curPrefix + strings.ToUpper(typeOf.Name()), + Pointer: value, + Kind: value.Kind(), + } + + parsedTree = append(parsedTree, f) + + printDebug("Field data constructed: %+v", f) + + return + } + for i := 0; i < value.NumField(); i++ { fieldToProcess := value.Field(i) fieldToProcessType := typeOf.Field(i) @@ -79,6 +104,16 @@ func composeTree(value reflect.Value, prefix string) { newElementPrefix = strings.ToUpper(newElementPrefix + typeOf.Field(i).Name) } composeTree(fieldToProcess, newElementPrefix) + } else if fieldToProcess.Kind() == reflect.Map { + newElementPrefix := curPrefix + if !fieldToProcessType.Anonymous { + newElementPrefix = strings.ToUpper(newElementPrefix + typeOf.Field(i).Name) + } + + mapIter := fieldToProcess.MapRange() + for mapIter.Next() { + composeTree(mapIter.Value().Elem(), newElementPrefix+"_"+strings.ToUpper(mapIter.Key().String())) + } } else { f := &field{ Name: typeOf.Field(i).Name, diff --git a/sec_test.go b/sec_test.go index 4a285b8..ce918f0 100644 --- a/sec_test.go +++ b/sec_test.go @@ -81,6 +81,10 @@ type testStruct1 struct { testUnexportedNest *testDatas } +type testStructWithMap struct { + MapConfig map[string]interface{} +} + func setenv(prefix string) { os.Setenv(prefix+"TESTSTRING", testString) os.Setenv(prefix+"TESTINT8", strconv.FormatInt(int64(testInt8), 10)) @@ -124,6 +128,8 @@ func TestParseValidData(t *testing.T) { setenv("TESTNESTINTERFACEPOINTER_") setenv("TESTNESTPOINTER_") setenv("TESTUNEXPORTEDNEST_") + setenv("MAPCONFIG_TESTSTRUCT_") + setenv("MAPCONFIG_TESTSTRUCT_TESTNEST_") ts := &testStruct1{} err := Parse(ts, nil) @@ -135,6 +141,15 @@ func TestParseValidData(t *testing.T) { require.Nil(t, err) require.Equal(t, testBool, ts.TestBool) + ts1 := &testStructWithMap{MapConfig: map[string]interface{}{ + "teststruct": &testStruct1{}, + }} + + err1 := Parse(ts1, nil) + require.Nil(t, err1) + + t.Logf("Parsed struct with map data: %+v\n", ts1.MapConfig["teststruct"]) + unsetenv("") unsetenv("TESTNEST_") unsetenv("TESTNESTANONYMOUS_") @@ -143,6 +158,8 @@ func TestParseValidData(t *testing.T) { unsetenv("TESTNESTINTERFACEPOINTER_") unsetenv("TESTNESTPOINTER_") unsetenv("TESTUNEXPORTEDNEST_") + unsetenv("MAPCONFIG_TESTSTRUCT_") + unsetenv("MAPCONFIG_TESTSTRUCT_TESTNEST_") } func TestParseNotPointerToStructurePassed(t *testing.T) {