From 3d006fe361ca4ea1ec973e39ce40f98aa3d2f2c9 Mon Sep 17 00:00:00 2001 From: Oleksandr Redko Date: Tue, 26 Sep 2023 17:59:38 +0300 Subject: [PATCH] refactor: replace interface{} with any --- README.md | 18 +- internal/encoding/decoder.go | 6 +- internal/encoding/decoder_test.go | 10 +- internal/encoding/dotenv/codec.go | 6 +- internal/encoding/dotenv/codec_test.go | 6 +- internal/encoding/dotenv/map_utils.go | 10 +- internal/encoding/encoder.go | 6 +- internal/encoding/encoder_test.go | 6 +- internal/encoding/hcl/codec.go | 4 +- internal/encoding/hcl/codec_test.go | 28 +-- internal/encoding/ini/codec.go | 6 +- internal/encoding/ini/codec_test.go | 20 +- internal/encoding/ini/map_utils.go | 18 +- internal/encoding/javaproperties/codec.go | 6 +- .../encoding/javaproperties/codec_test.go | 10 +- internal/encoding/javaproperties/map_utils.go | 18 +- internal/encoding/json/codec.go | 4 +- internal/encoding/json/codec_test.go | 16 +- internal/encoding/toml/codec.go | 4 +- internal/encoding/toml/codec_test.go | 16 +- internal/encoding/yaml/codec.go | 4 +- internal/encoding/yaml/codec_test.go | 28 +-- logger.go | 10 +- overrides_test.go | 30 +-- util.go | 36 ++-- util_test.go | 10 +- viper.go | 190 +++++++++--------- viper_test.go | 120 +++++------ 28 files changed, 322 insertions(+), 324 deletions(-) diff --git a/README.md b/README.md index f45188185..5cbcfc6f3 100644 --- a/README.md +++ b/README.md @@ -544,19 +544,19 @@ go func(){ In Viper, there are a few ways to get a value depending on the value’s type. The following functions and methods exist: - * `Get(key string) : interface{}` + * `Get(key string) : any` * `GetBool(key string) : bool` * `GetFloat64(key string) : float64` * `GetInt(key string) : int` * `GetIntSlice(key string) : []int` * `GetString(key string) : string` - * `GetStringMap(key string) : map[string]interface{}` + * `GetStringMap(key string) : map[string]any` * `GetStringMapString(key string) : map[string]string` * `GetStringSlice(key string) : []string` * `GetTime(key string) : time.Time` * `GetDuration(key string) : time.Duration` * `IsSet(key string) : bool` - * `AllSettings() : map[string]interface{}` + * `AllSettings() : map[string]any` One important thing to recognize is that each Get function will return a zero value if it’s not found. To check if a given key exists, the `IsSet()` method @@ -719,8 +719,8 @@ etc. There are two methods to do this: - * `Unmarshal(rawVal interface{}) : error` - * `UnmarshalKey(key string, rawVal interface{}) : error` + * `Unmarshal(rawVal any) : error` + * `UnmarshalKey(key string, rawVal any) : error` Example: @@ -745,9 +745,9 @@ you have to change the delimiter: ```go v := viper.NewWithOptions(viper.KeyDelimiter("::")) -v.SetDefault("chart::values", map[string]interface{}{ - "ingress": map[string]interface{}{ - "annotations": map[string]interface{}{ +v.SetDefault("chart::values", map[string]any{ + "ingress": map[string]any{ + "annotations": map[string]any{ "traefik.frontend.rule.type": "PathPrefix", "traefik.ingress.kubernetes.io/ssl-redirect": "true", }, @@ -756,7 +756,7 @@ v.SetDefault("chart::values", map[string]interface{}{ type config struct { Chart struct{ - Values map[string]interface{} + Values map[string]any } } diff --git a/internal/encoding/decoder.go b/internal/encoding/decoder.go index f472e9ff1..8a7b1dbc9 100644 --- a/internal/encoding/decoder.go +++ b/internal/encoding/decoder.go @@ -5,9 +5,9 @@ import ( ) // Decoder decodes the contents of b into v. -// It's primarily used for decoding contents of a file into a map[string]interface{}. +// It's primarily used for decoding contents of a file into a map[string]any. type Decoder interface { - Decode(b []byte, v map[string]interface{}) error + Decode(b []byte, v map[string]any) error } const ( @@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error { } // Decode calls the underlying Decoder based on the format. -func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]interface{}) error { +func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]any) error { e.mu.RLock() decoder, ok := e.decoders[format] e.mu.RUnlock() diff --git a/internal/encoding/decoder_test.go b/internal/encoding/decoder_test.go index 6cb56d021..0cd49fb61 100644 --- a/internal/encoding/decoder_test.go +++ b/internal/encoding/decoder_test.go @@ -6,10 +6,10 @@ import ( ) type decoder struct { - v map[string]interface{} + v map[string]any } -func (d decoder) Decode(_ []byte, v map[string]interface{}) error { +func (d decoder) Decode(_ []byte, v map[string]any) error { for key, value := range d.v { v[key] = value } @@ -46,7 +46,7 @@ func TestDecoderRegistry_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { registry := NewDecoderRegistry() decoder := decoder{ - v: map[string]interface{}{ + v: map[string]any{ "key": "value", }, } @@ -56,7 +56,7 @@ func TestDecoderRegistry_Decode(t *testing.T) { t.Fatal(err) } - v := map[string]interface{}{} + v := map[string]any{} err = registry.Decode("myformat", []byte("key: value"), v) if err != nil { @@ -71,7 +71,7 @@ func TestDecoderRegistry_Decode(t *testing.T) { t.Run("DecoderNotFound", func(t *testing.T) { registry := NewDecoderRegistry() - v := map[string]interface{}{} + v := map[string]any{} err := registry.Decode("myformat", nil, v) if err != ErrDecoderNotFound { diff --git a/internal/encoding/dotenv/codec.go b/internal/encoding/dotenv/codec.go index 4485063b6..3ebc76f02 100644 --- a/internal/encoding/dotenv/codec.go +++ b/internal/encoding/dotenv/codec.go @@ -15,8 +15,8 @@ const keyDelimiter = "_" // (commonly called as dotenv format). type Codec struct{} -func (Codec) Encode(v map[string]interface{}) ([]byte, error) { - flattened := map[string]interface{}{} +func (Codec) Encode(v map[string]any) ([]byte, error) { + flattened := map[string]any{} flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter) @@ -40,7 +40,7 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) { return buf.Bytes(), nil } -func (Codec) Decode(b []byte, v map[string]interface{}) error { +func (Codec) Decode(b []byte, v map[string]any) error { var buf bytes.Buffer _, err := buf.Write(b) diff --git a/internal/encoding/dotenv/codec_test.go b/internal/encoding/dotenv/codec_test.go index d297071c1..f9a6fb466 100644 --- a/internal/encoding/dotenv/codec_test.go +++ b/internal/encoding/dotenv/codec_test.go @@ -15,7 +15,7 @@ const encoded = `KEY=value ` // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "KEY": "value", } @@ -36,7 +36,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -51,7 +51,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/internal/encoding/dotenv/map_utils.go b/internal/encoding/dotenv/map_utils.go index aeb6b8722..1340c7308 100644 --- a/internal/encoding/dotenv/map_utils.go +++ b/internal/encoding/dotenv/map_utils.go @@ -9,25 +9,25 @@ import ( // flattenAndMergeMap recursively flattens the given map into a new map // Code is based on the function with the same name in the main package. // TODO: move it to a common place -func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} { +func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any { if shadow != nil && prefix != "" && shadow[prefix] != nil { // prefix is shadowed => nothing more to flatten return shadow } if shadow == nil { - shadow = make(map[string]interface{}) + shadow = make(map[string]any) } - var m2 map[string]interface{} + var m2 map[string]any if prefix != "" { prefix += delimiter } for k, val := range m { fullKey := prefix + k switch val := val.(type) { - case map[string]interface{}: + case map[string]any: m2 = val - case map[interface{}]interface{}: + case map[any]any: m2 = cast.ToStringMap(val) default: // immediate value diff --git a/internal/encoding/encoder.go b/internal/encoding/encoder.go index 2341bf235..659585962 100644 --- a/internal/encoding/encoder.go +++ b/internal/encoding/encoder.go @@ -5,9 +5,9 @@ import ( ) // Encoder encodes the contents of v into a byte representation. -// It's primarily used for encoding a map[string]interface{} into a file format. +// It's primarily used for encoding a map[string]any into a file format. type Encoder interface { - Encode(v map[string]interface{}) ([]byte, error) + Encode(v map[string]any) ([]byte, error) } const ( @@ -47,7 +47,7 @@ func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error { return nil } -func (e *EncoderRegistry) Encode(format string, v map[string]interface{}) ([]byte, error) { +func (e *EncoderRegistry) Encode(format string, v map[string]any) ([]byte, error) { e.mu.RLock() encoder, ok := e.encoders[format] e.mu.RUnlock() diff --git a/internal/encoding/encoder_test.go b/internal/encoding/encoder_test.go index adee6d090..795e868e1 100644 --- a/internal/encoding/encoder_test.go +++ b/internal/encoding/encoder_test.go @@ -8,7 +8,7 @@ type encoder struct { b []byte } -func (e encoder) Encode(_ map[string]interface{}) ([]byte, error) { +func (e encoder) Encode(_ map[string]any) ([]byte, error) { return e.b, nil } @@ -49,7 +49,7 @@ func TestEncoderRegistry_Decode(t *testing.T) { t.Fatal(err) } - b, err := registry.Encode("myformat", map[string]interface{}{"key": "value"}) + b, err := registry.Encode("myformat", map[string]any{"key": "value"}) if err != nil { t.Fatal(err) } @@ -62,7 +62,7 @@ func TestEncoderRegistry_Decode(t *testing.T) { t.Run("EncoderNotFound", func(t *testing.T) { registry := NewEncoderRegistry() - _, err := registry.Encode("myformat", map[string]interface{}{"key": "value"}) + _, err := registry.Encode("myformat", map[string]any{"key": "value"}) if err != ErrEncoderNotFound { t.Fatalf("expected ErrEncoderNotFound, got: %v", err) } diff --git a/internal/encoding/hcl/codec.go b/internal/encoding/hcl/codec.go index 7fde8e4bc..d7fa8a1b7 100644 --- a/internal/encoding/hcl/codec.go +++ b/internal/encoding/hcl/codec.go @@ -12,7 +12,7 @@ import ( // TODO: add printer config to the codec? type Codec struct{} -func (Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (Codec) Encode(v map[string]any) ([]byte, error) { b, err := json.Marshal(v) if err != nil { return nil, err @@ -35,6 +35,6 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) { return buf.Bytes(), nil } -func (Codec) Decode(b []byte, v map[string]interface{}) error { +func (Codec) Decode(b []byte, v map[string]any) error { return hcl.Unmarshal(b, &v) } diff --git a/internal/encoding/hcl/codec_test.go b/internal/encoding/hcl/codec_test.go index 7e48057c0..e0b1ebc20 100644 --- a/internal/encoding/hcl/codec_test.go +++ b/internal/encoding/hcl/codec_test.go @@ -45,24 +45,24 @@ const encoded = `"key" = "value" // // in case of HCL it's slightly different from Viper's internal representation // (eg. map is decoded into a list of maps) -var decoded = map[string]interface{}{ +var decoded = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": []map[string]interface{}{ + "map": []map[string]any{ { "key": "value", }, }, - "nested_map": []map[string]interface{}{ + "nested_map": []map[string]any{ { - "map": []map[string]interface{}{ + "map": []map[string]any{ { "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -74,20 +74,20 @@ var decoded = map[string]interface{}{ } // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, - "nested_map": map[string]interface{}{ - "map": map[string]interface{}{ + "nested_map": map[string]any{ + "map": map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -113,7 +113,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -128,7 +128,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/internal/encoding/ini/codec.go b/internal/encoding/ini/codec.go index 9acd87fc3..d91cf59d2 100644 --- a/internal/encoding/ini/codec.go +++ b/internal/encoding/ini/codec.go @@ -19,11 +19,11 @@ type Codec struct { LoadOptions LoadOptions } -func (c Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (c Codec) Encode(v map[string]any) ([]byte, error) { cfg := ini.Empty() ini.PrettyFormat = false - flattened := map[string]interface{}{} + flattened := map[string]any{} flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter()) @@ -62,7 +62,7 @@ func (c Codec) Encode(v map[string]interface{}) ([]byte, error) { return buf.Bytes(), nil } -func (c Codec) Decode(b []byte, v map[string]interface{}) error { +func (c Codec) Decode(b []byte, v map[string]any) error { cfg := ini.Empty(c.LoadOptions) err := cfg.Append(b) diff --git a/internal/encoding/ini/codec_test.go b/internal/encoding/ini/codec_test.go index e54812cb9..0b635d1a9 100644 --- a/internal/encoding/ini/codec_test.go +++ b/internal/encoding/ini/codec_test.go @@ -26,19 +26,19 @@ key=value // // in case of INI it's slightly different from Viper's internal representation // (eg. top level keys land in a section called default) -var decoded = map[string]interface{}{ - "DEFAULT": map[string]interface{}{ +var decoded = map[string]any{ + "DEFAULT": map[string]any{ "key": "value", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, } // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, } @@ -60,11 +60,11 @@ func TestCodec_Encode(t *testing.T) { t.Run("Default", func(t *testing.T) { codec := Codec{} - data := map[string]interface{}{ - "default": map[string]interface{}{ + data := map[string]any{ + "default": map[string]any{ "key": "value", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, } @@ -84,7 +84,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -99,7 +99,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/internal/encoding/ini/map_utils.go b/internal/encoding/ini/map_utils.go index 4fb9eb117..c1919a386 100644 --- a/internal/encoding/ini/map_utils.go +++ b/internal/encoding/ini/map_utils.go @@ -15,22 +15,22 @@ import ( // In case intermediate keys do not exist, or map to a non-map value, // a new map is created and inserted, and the search continues from there: // the initial map "m" may be modified! -func deepSearch(m map[string]interface{}, path []string) map[string]interface{} { +func deepSearch(m map[string]any, path []string) map[string]any { for _, k := range path { m2, ok := m[k] if !ok { // intermediate key does not exist // => create it and continue from there - m3 := make(map[string]interface{}) + m3 := make(map[string]any) m[k] = m3 m = m3 continue } - m3, ok := m2.(map[string]interface{}) + m3, ok := m2.(map[string]any) if !ok { // intermediate key is a value // => replace with a new map - m3 = make(map[string]interface{}) + m3 = make(map[string]any) m[k] = m3 } // continue search from here @@ -42,25 +42,25 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} // flattenAndMergeMap recursively flattens the given map into a new map // Code is based on the function with the same name in the main package. // TODO: move it to a common place -func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} { +func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any { if shadow != nil && prefix != "" && shadow[prefix] != nil { // prefix is shadowed => nothing more to flatten return shadow } if shadow == nil { - shadow = make(map[string]interface{}) + shadow = make(map[string]any) } - var m2 map[string]interface{} + var m2 map[string]any if prefix != "" { prefix += delimiter } for k, val := range m { fullKey := prefix + k switch val := val.(type) { - case map[string]interface{}: + case map[string]any: m2 = val - case map[interface{}]interface{}: + case map[any]any: m2 = cast.ToStringMap(val) default: // immediate value diff --git a/internal/encoding/javaproperties/codec.go b/internal/encoding/javaproperties/codec.go index b8a2251c1..e92e5172c 100644 --- a/internal/encoding/javaproperties/codec.go +++ b/internal/encoding/javaproperties/codec.go @@ -20,12 +20,12 @@ type Codec struct { Properties *properties.Properties } -func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (c *Codec) Encode(v map[string]any) ([]byte, error) { if c.Properties == nil { c.Properties = properties.NewProperties() } - flattened := map[string]interface{}{} + flattened := map[string]any{} flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter()) @@ -54,7 +54,7 @@ func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) { return buf.Bytes(), nil } -func (c *Codec) Decode(b []byte, v map[string]interface{}) error { +func (c *Codec) Decode(b []byte, v map[string]any) error { var err error c.Properties, err = properties.Load(b, properties.UTF8) if err != nil { diff --git a/internal/encoding/javaproperties/codec_test.go b/internal/encoding/javaproperties/codec_test.go index 0a33ebfdb..7c4f89897 100644 --- a/internal/encoding/javaproperties/codec_test.go +++ b/internal/encoding/javaproperties/codec_test.go @@ -17,9 +17,9 @@ map.key = value ` // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, } @@ -41,7 +41,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -58,7 +58,7 @@ func TestCodec_Decode(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} codec.Decode([]byte(``), v) @@ -71,7 +71,7 @@ func TestCodec_Decode(t *testing.T) { func TestCodec_DecodeEncode(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { diff --git a/internal/encoding/javaproperties/map_utils.go b/internal/encoding/javaproperties/map_utils.go index eb5379089..8386920aa 100644 --- a/internal/encoding/javaproperties/map_utils.go +++ b/internal/encoding/javaproperties/map_utils.go @@ -15,22 +15,22 @@ import ( // In case intermediate keys do not exist, or map to a non-map value, // a new map is created and inserted, and the search continues from there: // the initial map "m" may be modified! -func deepSearch(m map[string]interface{}, path []string) map[string]interface{} { +func deepSearch(m map[string]any, path []string) map[string]any { for _, k := range path { m2, ok := m[k] if !ok { // intermediate key does not exist // => create it and continue from there - m3 := make(map[string]interface{}) + m3 := make(map[string]any) m[k] = m3 m = m3 continue } - m3, ok := m2.(map[string]interface{}) + m3, ok := m2.(map[string]any) if !ok { // intermediate key is a value // => replace with a new map - m3 = make(map[string]interface{}) + m3 = make(map[string]any) m[k] = m3 } // continue search from here @@ -42,25 +42,25 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{} // flattenAndMergeMap recursively flattens the given map into a new map // Code is based on the function with the same name in the main package. // TODO: move it to a common place -func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} { +func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any { if shadow != nil && prefix != "" && shadow[prefix] != nil { // prefix is shadowed => nothing more to flatten return shadow } if shadow == nil { - shadow = make(map[string]interface{}) + shadow = make(map[string]any) } - var m2 map[string]interface{} + var m2 map[string]any if prefix != "" { prefix += delimiter } for k, val := range m { fullKey := prefix + k switch val := val.(type) { - case map[string]interface{}: + case map[string]any: m2 = val - case map[interface{}]interface{}: + case map[any]any: m2 = cast.ToStringMap(val) default: // immediate value diff --git a/internal/encoding/json/codec.go b/internal/encoding/json/codec.go index 1b7caaceb..da7546b5a 100644 --- a/internal/encoding/json/codec.go +++ b/internal/encoding/json/codec.go @@ -7,11 +7,11 @@ import ( // Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding. type Codec struct{} -func (Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (Codec) Encode(v map[string]any) ([]byte, error) { // TODO: expose prefix and indent in the Codec as setting? return json.MarshalIndent(v, "", " ") } -func (Codec) Decode(b []byte, v map[string]interface{}) error { +func (Codec) Decode(b []byte, v map[string]any) error { return json.Unmarshal(b, &v) } diff --git a/internal/encoding/json/codec_test.go b/internal/encoding/json/codec_test.go index f4a71df49..a1ec36093 100644 --- a/internal/encoding/json/codec_test.go +++ b/internal/encoding/json/codec_test.go @@ -29,20 +29,20 @@ const encoded = `{ }` // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, - "nested_map": map[string]interface{}{ - "map": map[string]interface{}{ + "nested_map": map[string]any{ + "map": map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -68,7 +68,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(encoded), v) if err != nil { @@ -83,7 +83,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/internal/encoding/toml/codec.go b/internal/encoding/toml/codec.go index a993c5994..c70aa8d28 100644 --- a/internal/encoding/toml/codec.go +++ b/internal/encoding/toml/codec.go @@ -7,10 +7,10 @@ import ( // Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding. type Codec struct{} -func (Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (Codec) Encode(v map[string]any) ([]byte, error) { return toml.Marshal(v) } -func (Codec) Decode(b []byte, v map[string]interface{}) error { +func (Codec) Decode(b []byte, v map[string]any) error { return toml.Unmarshal(b, &v) } diff --git a/internal/encoding/toml/codec_test.go b/internal/encoding/toml/codec_test.go index acbe905a4..b52f117fc 100644 --- a/internal/encoding/toml/codec_test.go +++ b/internal/encoding/toml/codec_test.go @@ -39,20 +39,20 @@ list = ['item1', 'item2', 'item3'] ` // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, - "nested_map": map[string]interface{}{ - "map": map[string]interface{}{ + "nested_map": map[string]any{ + "map": map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -78,7 +78,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -93,7 +93,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/internal/encoding/yaml/codec.go b/internal/encoding/yaml/codec.go index 82dc136a3..036879249 100644 --- a/internal/encoding/yaml/codec.go +++ b/internal/encoding/yaml/codec.go @@ -5,10 +5,10 @@ import "gopkg.in/yaml.v3" // Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding. type Codec struct{} -func (Codec) Encode(v map[string]interface{}) ([]byte, error) { +func (Codec) Encode(v map[string]any) ([]byte, error) { return yaml.Marshal(v) } -func (Codec) Decode(b []byte, v map[string]interface{}) error { +func (Codec) Decode(b []byte, v map[string]any) error { return yaml.Unmarshal(b, &v) } diff --git a/internal/encoding/yaml/codec_test.go b/internal/encoding/yaml/codec_test.go index 9fe3838a0..1a00a8383 100644 --- a/internal/encoding/yaml/codec_test.go +++ b/internal/encoding/yaml/codec_test.go @@ -47,20 +47,20 @@ nested_map: // // in case of YAML it's slightly different from Viper's internal representation // (eg. map is decoded into a map with interface key) -var decoded = map[string]interface{}{ +var decoded = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, - "nested_map": map[string]interface{}{ - "map": map[string]interface{}{ + "nested_map": map[string]any{ + "map": map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -70,20 +70,20 @@ var decoded = map[string]interface{}{ } // Viper's internal representation -var data = map[string]interface{}{ +var data = map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", }, - "map": map[string]interface{}{ + "map": map[string]any{ "key": "value", }, - "nested_map": map[string]interface{}{ - "map": map[string]interface{}{ + "nested_map": map[string]any{ + "map": map[string]any{ "key": "value", - "list": []interface{}{ + "list": []any{ "item1", "item2", "item3", @@ -109,7 +109,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("OK", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(original), v) if err != nil { @@ -124,7 +124,7 @@ func TestCodec_Decode(t *testing.T) { t.Run("InvalidData", func(t *testing.T) { codec := Codec{} - v := map[string]interface{}{} + v := map[string]any{} err := codec.Decode([]byte(`invalid data`), v) if err == nil { diff --git a/logger.go b/logger.go index ba0976155..8938053b3 100644 --- a/logger.go +++ b/logger.go @@ -16,30 +16,30 @@ type Logger interface { // // Even more fine-grained information than Debug events. // Loggers not supporting this level should fall back to Debug. - Trace(msg string, keyvals ...interface{}) + Trace(msg string, keyvals ...any) // Debug logs a Debug event. // // A verbose series of information events. // They are useful when debugging the system. - Debug(msg string, keyvals ...interface{}) + Debug(msg string, keyvals ...any) // Info logs an Info event. // // General information about what's happening inside the system. - Info(msg string, keyvals ...interface{}) + Info(msg string, keyvals ...any) // Warn logs a Warn(ing) event. // // Non-critical events that should be looked at. - Warn(msg string, keyvals ...interface{}) + Warn(msg string, keyvals ...any) // Error logs an Error event. // // Critical events that require immediate attention. // Loggers commonly provide Fatal and Panic levels above Error level, // but exiting and panicking is out of scope for a logging library. - Error(msg string, keyvals ...interface{}) + Error(msg string, keyvals ...any) } // WithLogger sets a custom logger. diff --git a/overrides_test.go b/overrides_test.go index 4491ea232..9ddfa80f2 100644 --- a/overrides_test.go +++ b/overrides_test.go @@ -46,11 +46,11 @@ func TestNestedOverrides(t *testing.T) { deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4) // Case 4: key:value overridden by a map - v = overrideDefault(assert, "tom.size", 4, "tom", map[string]interface{}{"age": 10}) // "tom.size" is first given "4" as default value, then "tom" is overridden by map{"age":10} - assert.Equal(4, v.Get("tom.size")) // "tom.size" should still be reachable - assert.Equal(10, v.Get("tom.age")) // new value should be there - deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) // new value should be there - v = override(assert, "tom.size", 4, "tom", map[string]interface{}{"age": 10}) + v = overrideDefault(assert, "tom.size", 4, "tom", map[string]any{"age": 10}) // "tom.size" is first given "4" as default value, then "tom" is overridden by map{"age":10} + assert.Equal(4, v.Get("tom.size")) // "tom.size" should still be reachable + assert.Equal(10, v.Get("tom.age")) // new value should be there + deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) // new value should be there + v = override(assert, "tom.size", 4, "tom", map[string]any{"age": 10}) assert.Nil(v.Get("tom.size")) assert.Equal(10, v.Get("tom.age")) deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) @@ -75,11 +75,11 @@ func TestNestedOverrides(t *testing.T) { } } -func overrideDefault(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper { +func overrideDefault(assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper { return overrideFromLayer(defaultLayer, assert, firstPath, firstValue, secondPath, secondValue) } -func override(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper { +func override(assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper { return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue) } @@ -94,7 +94,7 @@ func override(assert *assert.Assertions, firstPath string, firstValue interface{ // // After each assignment, the value is checked, retrieved both by its full path // and by its key sequence (successive maps). -func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper { +func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper { v := New() firstKeys := strings.Split(firstPath, v.keyDelim) if assert == nil || @@ -128,14 +128,14 @@ func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, fir // deepCheckValue checks that all given keys correspond to a valid path in the // configuration map of the given layer, and that the final value equals the one given -func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, value interface{}) { +func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, value any) { if assert == nil || v == nil || len(keys) == 0 || len(keys[0]) == 0 { return } // init - var val interface{} + var val any var ms string switch l { case defaultLayer: @@ -147,22 +147,22 @@ func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, } // loop through map - var m map[string]interface{} + var m map[string]any err := false for _, k := range keys { if val == nil { - assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms)) + assert.Fail(fmt.Sprintf("%s is not a map[string]any", ms)) return } // deep scan of the map to get the final value switch val := val.(type) { - case map[interface{}]interface{}: + case map[any]any: m = cast.ToStringMap(val) - case map[string]interface{}: + case map[string]any: m = val default: - assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms)) + assert.Fail(fmt.Sprintf("%s is not a map[string]any", ms)) return } ms = ms + "[\"" + k + "\"]" diff --git a/util.go b/util.go index 25c832c6a..52116ac44 100644 --- a/util.go +++ b/util.go @@ -39,11 +39,11 @@ func (pe ConfigParseError) Unwrap() error { // toCaseInsensitiveValue checks if the value is a map; // if so, create a copy and lower-case the keys recursively. -func toCaseInsensitiveValue(value interface{}) interface{} { +func toCaseInsensitiveValue(value any) any { switch v := value.(type) { - case map[interface{}]interface{}: + case map[any]any: value = copyAndInsensitiviseMap(cast.ToStringMap(v)) - case map[string]interface{}: + case map[string]any: value = copyAndInsensitiviseMap(v) } @@ -52,15 +52,15 @@ func toCaseInsensitiveValue(value interface{}) interface{} { // copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of // any map it makes case insensitive. -func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { - nm := make(map[string]interface{}) +func copyAndInsensitiviseMap(m map[string]any) map[string]any { + nm := make(map[string]any) for key, val := range m { lkey := strings.ToLower(key) switch v := val.(type) { - case map[interface{}]interface{}: + case map[any]any: nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v)) - case map[string]interface{}: + case map[string]any: nm[lkey] = copyAndInsensitiviseMap(v) default: nm[lkey] = v @@ -70,23 +70,23 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { return nm } -func insensitiviseVal(val interface{}) interface{} { +func insensitiviseVal(val any) any { switch v := val.(type) { - case map[interface{}]interface{}: + case map[any]any: // nested map: cast and recursively insensitivise val = cast.ToStringMap(val) - insensitiviseMap(val.(map[string]interface{})) - case map[string]interface{}: + insensitiviseMap(val.(map[string]any)) + case map[string]any: // nested map: recursively insensitivise insensitiviseMap(v) - case []interface{}: + case []any: // nested array: recursively insensitivise insensitiveArray(v) } return val } -func insensitiviseMap(m map[string]interface{}) { +func insensitiviseMap(m map[string]any) { for key, val := range m { val = insensitiviseVal(val) lower := strings.ToLower(key) @@ -99,7 +99,7 @@ func insensitiviseMap(m map[string]interface{}) { } } -func insensitiveArray(a []interface{}) { +func insensitiveArray(a []any) { for i, val := range a { a[i] = insensitiviseVal(val) } @@ -198,22 +198,22 @@ func parseSizeInBytes(sizeStr string) uint { // In case intermediate keys do not exist, or map to a non-map value, // a new map is created and inserted, and the search continues from there: // the initial map "m" may be modified! -func deepSearch(m map[string]interface{}, path []string) map[string]interface{} { +func deepSearch(m map[string]any, path []string) map[string]any { for _, k := range path { m2, ok := m[k] if !ok { // intermediate key does not exist // => create it and continue from there - m3 := make(map[string]interface{}) + m3 := make(map[string]any) m[k] = m3 m = m3 continue } - m3, ok := m2.(map[string]interface{}) + m3, ok := m2.(map[string]any) if !ok { // intermediate key is a value // => replace with a new map - m3 = make(map[string]interface{}) + m3 = make(map[string]any) m[k] = m3 } // continue search from here diff --git a/util_test.go b/util_test.go index 3740ea6b3..400d02db4 100644 --- a/util_test.go +++ b/util_test.go @@ -21,16 +21,16 @@ import ( func TestCopyAndInsensitiviseMap(t *testing.T) { var ( - given = map[string]interface{}{ + given = map[string]any{ "Foo": 32, - "Bar": map[interface{}]interface{}{ + "Bar": map[any]any{ "ABc": "A", "cDE": "B", }, } - expected = map[string]interface{}{ + expected = map[string]any{ "foo": 32, - "bar": map[string]interface{}{ + "bar": map[string]any{ "abc": "A", "cde": "B", }, @@ -51,7 +51,7 @@ func TestCopyAndInsensitiviseMap(t *testing.T) { t.Fatal("Input map changed") } - m := given["Bar"].(map[interface{}]interface{}) + m := given["Bar"].(map[any]any) if _, ok := m["ABc"]; !ok { t.Fatal("Input map changed") } diff --git a/viper.go b/viper.go index 097483be9..ffc5f70f5 100644 --- a/viper.go +++ b/viper.go @@ -207,10 +207,10 @@ type Viper struct { allowEmptyEnv bool parents []string - config map[string]interface{} - override map[string]interface{} - defaults map[string]interface{} - kvstore map[string]interface{} + config map[string]any + override map[string]any + defaults map[string]any + kvstore map[string]any pflags map[string]FlagValue env map[string][]string aliases map[string]string @@ -232,11 +232,11 @@ func New() *Viper { v.configName = "config" v.configPermissions = os.FileMode(0o644) v.fs = afero.NewOsFs() - v.config = make(map[string]interface{}) + v.config = make(map[string]any) v.parents = []string{} - v.override = make(map[string]interface{}) - v.defaults = make(map[string]interface{}) - v.kvstore = make(map[string]interface{}) + v.override = make(map[string]any) + v.defaults = make(map[string]any) + v.kvstore = make(map[string]any) v.pflags = make(map[string]FlagValue) v.env = make(map[string][]string) v.aliases = make(map[string]string) @@ -660,7 +660,7 @@ func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { // searchMap recursively searches for a value for path in source map. // Returns nil if not found. // Note: This assumes that the path entries and map keys are lower cased. -func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { +func (v *Viper) searchMap(source map[string]any, path []string) any { if len(path) == 0 { return source } @@ -674,9 +674,9 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac // Nested case switch next := next.(type) { - case map[interface{}]interface{}: + case map[any]any: return v.searchMap(cast.ToStringMap(next), path[1:]) - case map[string]interface{}: + case map[string]any: // Type assertion is safe here since it is only reached // if the type of `next` is the same as the type being asserted return v.searchMap(next, path[1:]) @@ -699,7 +699,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac // in their keys). // // Note: This assumes that the path entries and map keys are lower cased. -func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []string) interface{} { +func (v *Viper) searchIndexableWithPathPrefixes(source any, path []string) any { if len(path) == 0 { return source } @@ -708,11 +708,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin for i := len(path); i > 0; i-- { prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim)) - var val interface{} + var val any switch sourceIndexable := source.(type) { - case []interface{}: + case []any: val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path) - case map[string]interface{}: + case map[string]any: val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path) } if val != nil { @@ -729,11 +729,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin // This function is part of the searchIndexableWithPathPrefixes recurring search and // should not be called directly from functions other than searchIndexableWithPathPrefixes. func (v *Viper) searchSliceWithPathPrefixes( - sourceSlice []interface{}, + sourceSlice []any, prefixKey string, pathIndex int, path []string, -) interface{} { +) any { // if the prefixKey is not a number or it is out of bounds of the slice index, err := strconv.Atoi(prefixKey) if err != nil || len(sourceSlice) <= index { @@ -748,9 +748,9 @@ func (v *Viper) searchSliceWithPathPrefixes( } switch n := next.(type) { - case map[interface{}]interface{}: + case map[any]any: return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:]) - case map[string]interface{}, []interface{}: + case map[string]any, []any: return v.searchIndexableWithPathPrefixes(n, path[pathIndex:]) default: // got a value but nested key expected, do nothing and look for next prefix @@ -765,11 +765,11 @@ func (v *Viper) searchSliceWithPathPrefixes( // This function is part of the searchIndexableWithPathPrefixes recurring search and // should not be called directly from functions other than searchIndexableWithPathPrefixes. func (v *Viper) searchMapWithPathPrefixes( - sourceMap map[string]interface{}, + sourceMap map[string]any, prefixKey string, pathIndex int, path []string, -) interface{} { +) any { next, ok := sourceMap[prefixKey] if !ok { return nil @@ -782,9 +782,9 @@ func (v *Viper) searchMapWithPathPrefixes( // Nested case switch n := next.(type) { - case map[interface{}]interface{}: + case map[any]any: return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:]) - case map[string]interface{}, []interface{}: + case map[string]any, []any: return v.searchIndexableWithPathPrefixes(n, path[pathIndex:]) default: // got a value but nested key expected, do nothing and look for next prefix @@ -799,8 +799,8 @@ func (v *Viper) searchMapWithPathPrefixes( // e.g., if "foo.bar" has a value in the given map, it “shadows” // // "foo.bar.baz" in a lower-priority map -func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { - var parentVal interface{} +func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]any) string { + var parentVal any for i := 1; i < len(path); i++ { parentVal = v.searchMap(m, path[0:i]) if parentVal == nil { @@ -808,9 +808,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) return "" } switch parentVal.(type) { - case map[interface{}]interface{}: + case map[any]any: continue - case map[string]interface{}: + case map[string]any: continue default: // parentVal is a regular value which shadows "path" @@ -825,9 +825,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) // e.g., if "foo.bar" has a value in the given map, it “shadows” // // "foo.bar.baz" in a lower-priority map -func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { +func (v *Viper) isPathShadowedInFlatMap(path []string, mi any) string { // unify input map - var m map[string]interface{} + var m map[string]any switch mi.(type) { case map[string]string, map[string]FlagValue: m = cast.ToStringMap(mi) @@ -894,9 +894,9 @@ func GetViper() *Viper { // override, flag, env, config file, key/value store, default // // Get returns an interface. For a specific value use one of the Get____ methods. -func Get(key string) interface{} { return v.Get(key) } +func Get(key string) any { return v.Get(key) } -func (v *Viper) Get(key string) interface{} { +func (v *Viper) Get(key string) any { lcaseKey := strings.ToLower(key) val := v.find(lcaseKey, true) if val == nil { @@ -1066,9 +1066,9 @@ func (v *Viper) GetStringSlice(key string) []string { } // GetStringMap returns the value associated with the key as a map of interfaces. -func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } +func GetStringMap(key string) map[string]any { return v.GetStringMap(key) } -func (v *Viper) GetStringMap(key string) map[string]interface{} { +func (v *Viper) GetStringMap(key string) map[string]any { return cast.ToStringMap(v.Get(key)) } @@ -1096,27 +1096,27 @@ func (v *Viper) GetSizeInBytes(key string) uint { } // UnmarshalKey takes a single key and unmarshals it into a Struct. -func UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { +func UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error { return v.UnmarshalKey(key, rawVal, opts...) } -func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { +func (v *Viper) UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error { return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...)) } // Unmarshal unmarshals the config into a Struct. Make sure that the tags // on the fields of the structure are properly set. -func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { +func Unmarshal(rawVal any, opts ...DecoderConfigOption) error { return v.Unmarshal(rawVal, opts...) } -func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { +func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error { return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...)) } // defaultDecoderConfig returns default mapstructure.DecoderConfig with support // of time.Duration values & string slices -func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *mapstructure.DecoderConfig { +func defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure.DecoderConfig { c := &mapstructure.DecoderConfig{ Metadata: nil, Result: output, @@ -1133,7 +1133,7 @@ func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *maps } // A wrapper around mapstructure.Decode that mimics the WeakDecode functionality -func decode(input interface{}, config *mapstructure.DecoderConfig) error { +func decode(input any, config *mapstructure.DecoderConfig) error { decoder, err := mapstructure.NewDecoder(config) if err != nil { return err @@ -1143,11 +1143,11 @@ func decode(input interface{}, config *mapstructure.DecoderConfig) error { // UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent // in the destination struct. -func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error { +func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error { return v.UnmarshalExact(rawVal, opts...) } -func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error { +func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error { config := defaultDecoderConfig(rawVal, opts...) config.ErrorUnused = true @@ -1244,9 +1244,9 @@ func (v *Viper) MustBindEnv(input ...string) { // corresponds to a flag, the flag's default value is returned. // // Note: this assumes a lower-cased key given. -func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} { +func (v *Viper) find(lcaseKey string, flagDefault bool) any { var ( - val interface{} + val any exists bool path = strings.Split(lcaseKey, v.keyDelim) nested = len(path) > 1 @@ -1405,19 +1405,19 @@ func readAsCSV(val string) ([]string, error) { } // mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/master/string_to_string.go#L79 -// alterations are: errors are swallowed, map[string]interface{} is returned in order to enable cast.ToStringMap -func stringToStringConv(val string) interface{} { +// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap +func stringToStringConv(val string) any { val = strings.Trim(val, "[]") // An empty string would cause an empty map if len(val) == 0 { - return map[string]interface{}{} + return map[string]any{} } r := csv.NewReader(strings.NewReader(val)) ss, err := r.Read() if err != nil { return nil } - out := make(map[string]interface{}, len(ss)) + out := make(map[string]any, len(ss)) for _, pair := range ss { kv := strings.SplitN(pair, "=", 2) if len(kv) != 2 { @@ -1429,15 +1429,15 @@ func stringToStringConv(val string) interface{} { } // mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/string_to_int.go#L68 -// alterations are: errors are swallowed, map[string]interface{} is returned in order to enable cast.ToStringMap -func stringToIntConv(val string) interface{} { +// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap +func stringToIntConv(val string) any { val = strings.Trim(val, "[]") // An empty string would cause an empty map if len(val) == 0 { - return map[string]interface{}{} + return map[string]any{} } ss := strings.Split(val, ",") - out := make(map[string]interface{}, len(ss)) + out := make(map[string]any, len(ss)) for _, pair := range ss { kv := strings.SplitN(pair, "=", 2) if len(kv) != 2 { @@ -1545,9 +1545,9 @@ func (v *Viper) InConfig(key string) bool { // SetDefault sets the default value for this key. // SetDefault is case-insensitive for a key. // Default only used when no value is provided by the user via flag, config or ENV. -func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } +func SetDefault(key string, value any) { v.SetDefault(key, value) } -func (v *Viper) SetDefault(key string, value interface{}) { +func (v *Viper) SetDefault(key string, value any) { // If alias passed in, then set the proper default key = v.realKey(strings.ToLower(key)) value = toCaseInsensitiveValue(value) @@ -1564,9 +1564,9 @@ func (v *Viper) SetDefault(key string, value interface{}) { // Set is case-insensitive for a key. // Will be used instead of values obtained via // flags, config file, ENV, default, or key/value store. -func Set(key string, value interface{}) { v.Set(key, value) } +func Set(key string, value any) { v.Set(key, value) } -func (v *Viper) Set(key string, value interface{}) { +func (v *Viper) Set(key string, value any) { // If alias passed in, then set the proper override key = v.realKey(strings.ToLower(key)) value = toCaseInsensitiveValue(value) @@ -1600,7 +1600,7 @@ func (v *Viper) ReadInConfig() error { return err } - config := make(map[string]interface{}) + config := make(map[string]any) err = v.unmarshalReader(bytes.NewReader(file), config) if err != nil { @@ -1638,7 +1638,7 @@ func (v *Viper) MergeInConfig() error { func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } func (v *Viper) ReadConfig(in io.Reader) error { - v.config = make(map[string]interface{}) + v.config = make(map[string]any) return v.unmarshalReader(in, v.config) } @@ -1646,7 +1646,7 @@ func (v *Viper) ReadConfig(in io.Reader) error { func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } func (v *Viper) MergeConfig(in io.Reader) error { - cfg := make(map[string]interface{}) + cfg := make(map[string]any) if err := v.unmarshalReader(in, cfg); err != nil { return err } @@ -1655,11 +1655,11 @@ func (v *Viper) MergeConfig(in io.Reader) error { // MergeConfigMap merges the configuration from the map given with an existing config. // Note that the map given may be modified. -func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) } +func MergeConfigMap(cfg map[string]any) error { return v.MergeConfigMap(cfg) } -func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error { +func (v *Viper) MergeConfigMap(cfg map[string]any) error { if v.config == nil { - v.config = make(map[string]interface{}) + v.config = make(map[string]any) } insensitiviseMap(cfg) mergeMaps(cfg, v.config, nil) @@ -1724,7 +1724,7 @@ func (v *Viper) writeConfig(filename string, force bool) error { return UnsupportedConfigError(configType) } if v.config == nil { - v.config = make(map[string]interface{}) + v.config = make(map[string]any) } flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY if !force { @@ -1745,11 +1745,11 @@ func (v *Viper) writeConfig(filename string, force bool) error { // Unmarshal a Reader into a map. // Should probably be an unexported function. -func unmarshalReader(in io.Reader, c map[string]interface{}) error { +func unmarshalReader(in io.Reader, c map[string]any) error { return v.unmarshalReader(in, c) } -func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { +func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error { buf := new(bytes.Buffer) buf.ReadFrom(in) @@ -1783,7 +1783,7 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error { return nil } -func keyExists(k string, m map[string]interface{}) string { +func keyExists(k string, m map[string]any) string { lk := strings.ToLower(k) for mk := range m { lmk := strings.ToLower(mk) @@ -1795,33 +1795,33 @@ func keyExists(k string, m map[string]interface{}) string { } func castToMapStringInterface( - src map[interface{}]interface{}, -) map[string]interface{} { - tgt := map[string]interface{}{} + src map[any]any, +) map[string]any { + tgt := map[string]any{} for k, v := range src { tgt[fmt.Sprintf("%v", k)] = v } return tgt } -func castMapStringSliceToMapInterface(src map[string][]string) map[string]interface{} { - tgt := map[string]interface{}{} +func castMapStringSliceToMapInterface(src map[string][]string) map[string]any { + tgt := map[string]any{} for k, v := range src { tgt[k] = v } return tgt } -func castMapStringToMapInterface(src map[string]string) map[string]interface{} { - tgt := map[string]interface{}{} +func castMapStringToMapInterface(src map[string]string) map[string]any { + tgt := map[string]any{} for k, v := range src { tgt[k] = v } return tgt } -func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} { - tgt := map[string]interface{}{} +func castMapFlagToMapInterface(src map[string]FlagValue) map[string]any { + tgt := map[string]any{} for k, v := range src { tgt[k] = v } @@ -1829,13 +1829,11 @@ func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} } // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's -// insistence on parsing nested structures as `map[interface{}]interface{}` +// insistence on parsing nested structures as `map[any]any` // instead of using a `string` as the key for nest structures beyond one level // deep. Both map types are supported as there is a go-yaml fork that uses -// `map[string]interface{}` instead. -func mergeMaps( - src, tgt map[string]interface{}, itgt map[interface{}]interface{}, -) { +// `map[string]any` instead. +func mergeMaps(src, tgt map[string]any, itgt map[any]any) { for sk, sv := range src { tk := keyExists(sk, tgt) if tk == "" { @@ -1870,12 +1868,12 @@ func mergeMaps( ) switch ttv := tv.(type) { - case map[interface{}]interface{}: + case map[any]any: v.logger.Debug("merging maps (must convert)") - tsv, ok := sv.(map[interface{}]interface{}) + tsv, ok := sv.(map[any]any) if !ok { v.logger.Error( - "Could not cast sv to map[interface{}]interface{}", + "Could not cast sv to map[any]any", "key", sk, "st", svType, "tt", tvType, @@ -1888,12 +1886,12 @@ func mergeMaps( ssv := castToMapStringInterface(tsv) stv := castToMapStringInterface(ttv) mergeMaps(ssv, stv, ttv) - case map[string]interface{}: + case map[string]any: v.logger.Debug("merging maps") - tsv, ok := sv.(map[string]interface{}) + tsv, ok := sv.(map[string]any) if !ok { v.logger.Error( - "Could not cast sv to map[string]interface{}", + "Could not cast sv to map[string]any", "key", sk, "st", svType, "tt", tvType, @@ -1955,7 +1953,7 @@ func (v *Viper) getKeyValueConfig() error { return RemoteConfigError("No Files Found") } -func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { +func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) { reader, err := RemoteConfig.Get(provider) if err != nil { return nil, err @@ -2004,7 +2002,7 @@ func (v *Viper) watchKeyValueConfig() error { return RemoteConfigError("No Files Found") } -func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { +func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) { reader, err := RemoteConfig.Watch(provider) if err != nil { return nil, err @@ -2043,7 +2041,7 @@ func (v *Viper) AllKeys() []string { // it is skipped. // // The resulting set of paths is merged to the given shadow set at the same time. -func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { +func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]any, prefix string) map[string]bool { if shadow != nil && prefix != "" && shadow[prefix] { // prefix is shadowed => nothing more to flatten return shadow @@ -2052,16 +2050,16 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac shadow = make(map[string]bool) } - var m2 map[string]interface{} + var m2 map[string]any if prefix != "" { prefix += v.keyDelim } for k, val := range m { fullKey := prefix + k switch val := val.(type) { - case map[string]interface{}: + case map[string]any: m2 = val - case map[interface{}]interface{}: + case map[any]any: m2 = cast.ToStringMap(val) default: // immediate value @@ -2076,7 +2074,7 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac // mergeFlatMap merges the given maps, excluding values of the second map // shadowed by values from the first map. -func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool { +func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]any) map[string]bool { // scan keys outer: for k := range m { @@ -2096,11 +2094,11 @@ outer: return shadow } -// AllSettings merges all settings and returns them as a map[string]interface{}. -func AllSettings() map[string]interface{} { return v.AllSettings() } +// AllSettings merges all settings and returns them as a map[string]any. +func AllSettings() map[string]any { return v.AllSettings() } -func (v *Viper) AllSettings() map[string]interface{} { - m := map[string]interface{}{} +func (v *Viper) AllSettings() map[string]any { + m := map[string]any{} // start from the list of keys, and construct the map one value at a time for _, k := range v.AllKeys() { value := v.Get(k) diff --git a/viper_test.go b/viper_test.go index 23f8b141a..b21263d4a 100644 --- a/viper_test.go +++ b/viper_test.go @@ -496,8 +496,8 @@ func TestUnmarshaling(t *testing.T) { assert.False(t, InConfig("state")) assert.False(t, InConfig("clothing.hat")) assert.Equal(t, "steve", Get("name")) - assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies")) - assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing")) + assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, Get("hobbies")) + assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, Get("clothing")) assert.Equal(t, 35, Get("age")) } @@ -774,14 +774,14 @@ func TestAllKeys(t *testing.T) { "name_dotenv", } dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") - all := map[string]interface{}{ - "owner": map[string]interface{}{ + all := map[string]any{ + "owner": map[string]any{ "organization": "MongoDB", "bio": "MongoDB Chief Developer Advocate & Hacker at Large", "dob": dob, }, "title": "TOML Example", - "author": map[string]interface{}{ + "author": map[string]any{ "e-mail": "fake@localhost", "github": "https://github.com/Unknown", "name": "Unknown", @@ -789,28 +789,28 @@ func TestAllKeys(t *testing.T) { }, "ppu": 0.55, "eyes": "brown", - "clothing": map[string]interface{}{ + "clothing": map[string]any{ "trousers": "denim", "jacket": "leather", - "pants": map[string]interface{}{"size": "large"}, + "pants": map[string]any{"size": "large"}, }, - "default": map[string]interface{}{ + "default": map[string]any{ "import_path": "gopkg.in/ini.v1", "name": "ini", "version": "v1", }, "id": "0001", - "batters": map[string]interface{}{ - "batter": []interface{}{ - map[string]interface{}{"type": "Regular"}, - map[string]interface{}{"type": "Chocolate"}, - map[string]interface{}{"type": "Blueberry"}, - map[string]interface{}{"type": "Devil's Food"}, + "batters": map[string]any{ + "batter": []any{ + map[string]any{"type": "Regular"}, + map[string]any{"type": "Chocolate"}, + map[string]any{"type": "Blueberry"}, + map[string]any{"type": "Devil's Food"}, }, }, "hacker": true, "beard": true, - "hobbies": []interface{}{ + "hobbies": []any{ "skateboarding", "snowboarding", "go", @@ -822,13 +822,13 @@ func TestAllKeys(t *testing.T) { "p_id": "0001", "p_ppu": "0.55", "p_name": "Cake", - "p_batters": map[string]interface{}{ - "batter": map[string]interface{}{"type": "Regular"}, + "p_batters": map[string]any{ + "batter": map[string]any{"type": "Regular"}, }, "p_type": "donut", - "foos": []map[string]interface{}{ + "foos": []map[string]any{ { - "foo": []map[string]interface{}{ + "foo": []map[string]any{ {"key": 1}, {"key": 2}, {"key": 3}, @@ -937,7 +937,7 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) { mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), // Custom Decode Hook Function - func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) { + func(rf reflect.Kind, rt reflect.Kind, data any) (any, error) { if rf != reflect.String || rt != reflect.Map { return data, nil } @@ -1328,38 +1328,38 @@ func TestFindsNestedKeys(t *testing.T) { initConfigs() dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") - Set("super", map[string]interface{}{ - "deep": map[string]interface{}{ + Set("super", map[string]any{ + "deep": map[string]any{ "nested": "value", }, }) - expected := map[string]interface{}{ - "super": map[string]interface{}{ - "deep": map[string]interface{}{ + expected := map[string]any{ + "super": map[string]any{ + "deep": map[string]any{ "nested": "value", }, }, - "super.deep": map[string]interface{}{ + "super.deep": map[string]any{ "nested": "value", }, "super.deep.nested": "value", "owner.organization": "MongoDB", - "batters.batter": []interface{}{ - map[string]interface{}{ + "batters.batter": []any{ + map[string]any{ "type": "Regular", }, - map[string]interface{}{ + map[string]any{ "type": "Chocolate", }, - map[string]interface{}{ + map[string]any{ "type": "Blueberry", }, - map[string]interface{}{ + map[string]any{ "type": "Devil's Food", }, }, - "hobbies": []interface{}{ + "hobbies": []any{ "skateboarding", "snowboarding", "go", }, "TITLE_DOTENV": "DotEnv Example", @@ -1367,25 +1367,25 @@ func TestFindsNestedKeys(t *testing.T) { "NAME_DOTENV": "Cake", "title": "TOML Example", "newkey": "remote", - "batters": map[string]interface{}{ - "batter": []interface{}{ - map[string]interface{}{ + "batters": map[string]any{ + "batter": []any{ + map[string]any{ "type": "Regular", }, - map[string]interface{}{ + map[string]any{ "type": "Chocolate", }, - map[string]interface{}{ + map[string]any{ "type": "Blueberry", }, - map[string]interface{}{ + map[string]any{ "type": "Devil's Food", }, }, }, "eyes": "brown", "age": 35, - "owner": map[string]interface{}{ + "owner": map[string]any{ "organization": "MongoDB", "bio": "MongoDB Chief Developer Advocate & Hacker at Large", "dob": dob, @@ -1396,10 +1396,10 @@ func TestFindsNestedKeys(t *testing.T) { "name": "Cake", "hacker": true, "ppu": 0.55, - "clothing": map[string]interface{}{ + "clothing": map[string]any{ "jacket": "leather", "trousers": "denim", - "pants": map[string]interface{}{ + "pants": map[string]any{ "size": "large", }, }, @@ -1408,9 +1408,9 @@ func TestFindsNestedKeys(t *testing.T) { "clothing.trousers": "denim", "owner.dob": dob, "beard": true, - "foos": []map[string]interface{}{ + "foos": []map[string]any{ { - "foo": []map[string]interface{}{ + "foo": []map[string]any{ { "key": 1, }, @@ -1444,8 +1444,8 @@ func TestReadBufConfig(t *testing.T) { assert.False(t, v.InConfig("state")) assert.False(t, v.InConfig("clothing.hat")) assert.Equal(t, "steve", v.Get("name")) - assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) - assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing")) + assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) + assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, v.Get("clothing")) assert.Equal(t, 35, v.Get("age")) } @@ -2180,11 +2180,11 @@ func TestMergeConfigMap(t *testing.T) { assert(37890) - update := map[string]interface{}{ - "Hello": map[string]interface{}{ + update := map[string]any{ + "Hello": map[string]any{ "Pop": 1234, }, - "World": map[interface{}]interface{}{ + "World": map[any]any{ "Rock": 345, }, } @@ -2255,7 +2255,7 @@ clothing: assert.Nil(t, Get("clothing.jacket.price")) assert.Equal(t, polyester, GetString("clothing.shirt")) - clothingSettings := AllSettings()["clothing"].(map[string]interface{}) + clothingSettings := AllSettings()["clothing"].(map[string]any) assert.Equal(t, "leather", clothingSettings["jacket"]) assert.Equal(t, polyester, clothingSettings["shirt"]) } @@ -2267,7 +2267,7 @@ func TestDotParameter(t *testing.T) { unmarshalReader(r, v.config) actual := Get("batters.batter") - expected := []interface{}{map[string]interface{}{"type": "Small"}} + expected := []any{map[string]any{"type": "Small"}} assert.Equal(t, expected, actual) } @@ -2318,17 +2318,17 @@ R = 6 func TestCaseInsensitiveSet(t *testing.T) { Reset() - m1 := map[string]interface{}{ + m1 := map[string]any{ "Foo": 32, - "Bar": map[interface{}]interface{}{ + "Bar": map[any]any{ "ABc": "A", "cDE": "B", }, } - m2 := map[string]interface{}{ + m2 := map[string]any{ "Foo": 52, - "Bar": map[interface{}]interface{}{ + "Bar": map[any]any{ "bCd": "A", "eFG": "B", }, @@ -2559,13 +2559,13 @@ func TestKeyDelimiter(t *testing.T) { err := v.unmarshalReader(r, v.config) require.NoError(t, err) - values := map[string]interface{}{ - "image": map[string]interface{}{ + values := map[string]any{ + "image": map[string]any{ "repository": "someImage", "tag": "1.0.0", }, - "ingress": map[string]interface{}{ - "annotations": map[string]interface{}{ + "ingress": map[string]any{ + "annotations": map[string]any{ "traefik.frontend.rule.type": "PathPrefix", "traefik.ingress.kubernetes.io/ssl-redirect": "true", }, @@ -2579,13 +2579,13 @@ func TestKeyDelimiter(t *testing.T) { type config struct { Charts struct { - Values map[string]interface{} + Values map[string]any } } expected := config{ Charts: struct { - Values map[string]interface{} + Values map[string]any }{ Values: values, },