diff --git a/viper.go b/viper.go index 2d5158cbd..12d121da3 100644 --- a/viper.go +++ b/viper.go @@ -68,6 +68,14 @@ func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption { } } +// DecodeSquash returns a DecoderConfigOption that configures whether +// embedded/anonymous fields are squashed into the parent structure during decoding. +func DecodeSquash(squash bool) DecoderConfigOption { + return func(c *mapstructure.DecoderConfig) { + c.Squash = squash + } +} + // Viper is a prioritized configuration registry. It // maintains a set of configuration sources, fetches // values to populate those, and provides them according diff --git a/viper_test.go b/viper_test.go index 8b0232aee..fc738dc4c 100644 --- a/viper_test.go +++ b/viper_test.go @@ -964,6 +964,23 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) { }, &C) } +func TestUnmarshalEmbeddedUnexportedStruct(t *testing.T) { + v := New() + v.Set("field", "value") + + type unexportedConfig struct { + Field string + } + + type config struct { + unexportedConfig + } + + var cfg config + require.NoError(t, v.Unmarshal(&cfg, DecodeSquash(true))) + assert.Equal(t, "value", cfg.Field) +} + func TestUnmarshalWithAutomaticEnv(t *testing.T) { t.Setenv("PORT", "1313") t.Setenv("NAME", "Steve")