refactor: replace interface{} with any

This commit is contained in:
Oleksandr Redko 2023-09-26 17:59:38 +03:00 committed by Márk Sági-Kazár
parent 8a6dc5d43c
commit 3d006fe361
28 changed files with 322 additions and 324 deletions

View file

@ -544,19 +544,19 @@ go func(){
In Viper, there are a few ways to get a value depending on the values type. In Viper, there are a few ways to get a value depending on the values type.
The following functions and methods exist: The following functions and methods exist:
* `Get(key string) : interface{}` * `Get(key string) : any`
* `GetBool(key string) : bool` * `GetBool(key string) : bool`
* `GetFloat64(key string) : float64` * `GetFloat64(key string) : float64`
* `GetInt(key string) : int` * `GetInt(key string) : int`
* `GetIntSlice(key string) : []int` * `GetIntSlice(key string) : []int`
* `GetString(key string) : string` * `GetString(key string) : string`
* `GetStringMap(key string) : map[string]interface{}` * `GetStringMap(key string) : map[string]any`
* `GetStringMapString(key string) : map[string]string` * `GetStringMapString(key string) : map[string]string`
* `GetStringSlice(key string) : []string` * `GetStringSlice(key string) : []string`
* `GetTime(key string) : time.Time` * `GetTime(key string) : time.Time`
* `GetDuration(key string) : time.Duration` * `GetDuration(key string) : time.Duration`
* `IsSet(key string) : bool` * `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 One important thing to recognize is that each Get function will return a zero
value if its not found. To check if a given key exists, the `IsSet()` method value if its not found. To check if a given key exists, the `IsSet()` method
@ -719,8 +719,8 @@ etc.
There are two methods to do this: There are two methods to do this:
* `Unmarshal(rawVal interface{}) : error` * `Unmarshal(rawVal any) : error`
* `UnmarshalKey(key string, rawVal interface{}) : error` * `UnmarshalKey(key string, rawVal any) : error`
Example: Example:
@ -745,9 +745,9 @@ you have to change the delimiter:
```go ```go
v := viper.NewWithOptions(viper.KeyDelimiter("::")) v := viper.NewWithOptions(viper.KeyDelimiter("::"))
v.SetDefault("chart::values", map[string]interface{}{ v.SetDefault("chart::values", map[string]any{
"ingress": map[string]interface{}{ "ingress": map[string]any{
"annotations": map[string]interface{}{ "annotations": map[string]any{
"traefik.frontend.rule.type": "PathPrefix", "traefik.frontend.rule.type": "PathPrefix",
"traefik.ingress.kubernetes.io/ssl-redirect": "true", "traefik.ingress.kubernetes.io/ssl-redirect": "true",
}, },
@ -756,7 +756,7 @@ v.SetDefault("chart::values", map[string]interface{}{
type config struct { type config struct {
Chart struct{ Chart struct{
Values map[string]interface{} Values map[string]any
} }
} }

View file

@ -5,9 +5,9 @@ import (
) )
// Decoder decodes the contents of b into v. // 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 { type Decoder interface {
Decode(b []byte, v map[string]interface{}) error Decode(b []byte, v map[string]any) error
} }
const ( const (
@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
} }
// Decode calls the underlying Decoder based on the format. // 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() e.mu.RLock()
decoder, ok := e.decoders[format] decoder, ok := e.decoders[format]
e.mu.RUnlock() e.mu.RUnlock()

View file

@ -6,10 +6,10 @@ import (
) )
type decoder struct { 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 { for key, value := range d.v {
v[key] = value v[key] = value
} }
@ -46,7 +46,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
registry := NewDecoderRegistry() registry := NewDecoderRegistry()
decoder := decoder{ decoder := decoder{
v: map[string]interface{}{ v: map[string]any{
"key": "value", "key": "value",
}, },
} }
@ -56,7 +56,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
v := map[string]interface{}{} v := map[string]any{}
err = registry.Decode("myformat", []byte("key: value"), v) err = registry.Decode("myformat", []byte("key: value"), v)
if err != nil { if err != nil {
@ -71,7 +71,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Run("DecoderNotFound", func(t *testing.T) { t.Run("DecoderNotFound", func(t *testing.T) {
registry := NewDecoderRegistry() registry := NewDecoderRegistry()
v := map[string]interface{}{} v := map[string]any{}
err := registry.Decode("myformat", nil, v) err := registry.Decode("myformat", nil, v)
if err != ErrDecoderNotFound { if err != ErrDecoderNotFound {

View file

@ -15,8 +15,8 @@ const keyDelimiter = "_"
// (commonly called as dotenv format). // (commonly called as dotenv format).
type Codec struct{} type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) { func (Codec) Encode(v map[string]any) ([]byte, error) {
flattened := map[string]interface{}{} flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter) flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter)
@ -40,7 +40,7 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil 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 var buf bytes.Buffer
_, err := buf.Write(b) _, err := buf.Write(b)

View file

@ -15,7 +15,7 @@ const encoded = `KEY=value
` `
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"KEY": "value", "KEY": "value",
} }
@ -36,7 +36,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -51,7 +51,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -9,25 +9,25 @@ import (
// flattenAndMergeMap recursively flattens the given map into a new map // flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in the main package. // Code is based on the function with the same name in the main package.
// TODO: move it to a common place // 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 { if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten // prefix is shadowed => nothing more to flatten
return shadow return shadow
} }
if shadow == nil { 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 != "" { if prefix != "" {
prefix += delimiter prefix += delimiter
} }
for k, val := range m { for k, val := range m {
fullKey := prefix + k fullKey := prefix + k
switch val := val.(type) { switch val := val.(type) {
case map[string]interface{}: case map[string]any:
m2 = val m2 = val
case map[interface{}]interface{}: case map[any]any:
m2 = cast.ToStringMap(val) m2 = cast.ToStringMap(val)
default: default:
// immediate value // immediate value

View file

@ -5,9 +5,9 @@ import (
) )
// Encoder encodes the contents of v into a byte representation. // 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 { type Encoder interface {
Encode(v map[string]interface{}) ([]byte, error) Encode(v map[string]any) ([]byte, error)
} }
const ( const (
@ -47,7 +47,7 @@ func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
return nil 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() e.mu.RLock()
encoder, ok := e.encoders[format] encoder, ok := e.encoders[format]
e.mu.RUnlock() e.mu.RUnlock()

View file

@ -8,7 +8,7 @@ type encoder struct {
b []byte b []byte
} }
func (e encoder) Encode(_ map[string]interface{}) ([]byte, error) { func (e encoder) Encode(_ map[string]any) ([]byte, error) {
return e.b, nil return e.b, nil
} }
@ -49,7 +49,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -62,7 +62,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
t.Run("EncoderNotFound", func(t *testing.T) { t.Run("EncoderNotFound", func(t *testing.T) {
registry := NewEncoderRegistry() registry := NewEncoderRegistry()
_, err := registry.Encode("myformat", map[string]interface{}{"key": "value"}) _, err := registry.Encode("myformat", map[string]any{"key": "value"})
if err != ErrEncoderNotFound { if err != ErrEncoderNotFound {
t.Fatalf("expected ErrEncoderNotFound, got: %v", err) t.Fatalf("expected ErrEncoderNotFound, got: %v", err)
} }

View file

@ -12,7 +12,7 @@ import (
// TODO: add printer config to the codec? // TODO: add printer config to the codec?
type Codec struct{} 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) b, err := json.Marshal(v)
if err != nil { if err != nil {
return nil, err return nil, err
@ -35,6 +35,6 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil 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) return hcl.Unmarshal(b, &v)
} }

View file

@ -45,24 +45,24 @@ const encoded = `"key" = "value"
// //
// in case of HCL it's slightly different from Viper's internal representation // in case of HCL it's slightly different from Viper's internal representation
// (eg. map is decoded into a list of maps) // (eg. map is decoded into a list of maps)
var decoded = map[string]interface{}{ var decoded = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": []map[string]interface{}{ "map": []map[string]any{
{ {
"key": "value", "key": "value",
}, },
}, },
"nested_map": []map[string]interface{}{ "nested_map": []map[string]any{
{ {
"map": []map[string]interface{}{ "map": []map[string]any{
{ {
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -74,20 +74,20 @@ var decoded = map[string]interface{}{
} }
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
"nested_map": map[string]interface{}{ "nested_map": map[string]any{
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -113,7 +113,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -128,7 +128,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -19,11 +19,11 @@ type Codec struct {
LoadOptions LoadOptions 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() cfg := ini.Empty()
ini.PrettyFormat = false ini.PrettyFormat = false
flattened := map[string]interface{}{} flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter()) flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
@ -62,7 +62,7 @@ func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil 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) cfg := ini.Empty(c.LoadOptions)
err := cfg.Append(b) err := cfg.Append(b)

View file

@ -26,19 +26,19 @@ key=value
// //
// in case of INI it's slightly different from Viper's internal representation // in case of INI it's slightly different from Viper's internal representation
// (eg. top level keys land in a section called default) // (eg. top level keys land in a section called default)
var decoded = map[string]interface{}{ var decoded = map[string]any{
"DEFAULT": map[string]interface{}{ "DEFAULT": map[string]any{
"key": "value", "key": "value",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
} }
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
} }
@ -60,11 +60,11 @@ func TestCodec_Encode(t *testing.T) {
t.Run("Default", func(t *testing.T) { t.Run("Default", func(t *testing.T) {
codec := Codec{} codec := Codec{}
data := map[string]interface{}{ data := map[string]any{
"default": map[string]interface{}{ "default": map[string]any{
"key": "value", "key": "value",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
} }
@ -84,7 +84,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -99,7 +99,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -15,22 +15,22 @@ import (
// In case intermediate keys do not exist, or map to a non-map value, // 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: // a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified! // 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 { for _, k := range path {
m2, ok := m[k] m2, ok := m[k]
if !ok { if !ok {
// intermediate key does not exist // intermediate key does not exist
// => create it and continue from there // => create it and continue from there
m3 := make(map[string]interface{}) m3 := make(map[string]any)
m[k] = m3 m[k] = m3
m = m3 m = m3
continue continue
} }
m3, ok := m2.(map[string]interface{}) m3, ok := m2.(map[string]any)
if !ok { if !ok {
// intermediate key is a value // intermediate key is a value
// => replace with a new map // => replace with a new map
m3 = make(map[string]interface{}) m3 = make(map[string]any)
m[k] = m3 m[k] = m3
} }
// continue search from here // 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 // flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in the main package. // Code is based on the function with the same name in the main package.
// TODO: move it to a common place // 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 { if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten // prefix is shadowed => nothing more to flatten
return shadow return shadow
} }
if shadow == nil { 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 != "" { if prefix != "" {
prefix += delimiter prefix += delimiter
} }
for k, val := range m { for k, val := range m {
fullKey := prefix + k fullKey := prefix + k
switch val := val.(type) { switch val := val.(type) {
case map[string]interface{}: case map[string]any:
m2 = val m2 = val
case map[interface{}]interface{}: case map[any]any:
m2 = cast.ToStringMap(val) m2 = cast.ToStringMap(val)
default: default:
// immediate value // immediate value

View file

@ -20,12 +20,12 @@ type Codec struct {
Properties *properties.Properties 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 { if c.Properties == nil {
c.Properties = properties.NewProperties() c.Properties = properties.NewProperties()
} }
flattened := map[string]interface{}{} flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter()) flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
@ -54,7 +54,7 @@ func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil 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 var err error
c.Properties, err = properties.Load(b, properties.UTF8) c.Properties, err = properties.Load(b, properties.UTF8)
if err != nil { if err != nil {

View file

@ -17,9 +17,9 @@ map.key = value
` `
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
} }
@ -41,7 +41,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -58,7 +58,7 @@ func TestCodec_Decode(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
codec.Decode([]byte(``), v) codec.Decode([]byte(``), v)
@ -71,7 +71,7 @@ func TestCodec_Decode(t *testing.T) {
func TestCodec_DecodeEncode(t *testing.T) { func TestCodec_DecodeEncode(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {

View file

@ -15,22 +15,22 @@ import (
// In case intermediate keys do not exist, or map to a non-map value, // 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: // a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified! // 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 { for _, k := range path {
m2, ok := m[k] m2, ok := m[k]
if !ok { if !ok {
// intermediate key does not exist // intermediate key does not exist
// => create it and continue from there // => create it and continue from there
m3 := make(map[string]interface{}) m3 := make(map[string]any)
m[k] = m3 m[k] = m3
m = m3 m = m3
continue continue
} }
m3, ok := m2.(map[string]interface{}) m3, ok := m2.(map[string]any)
if !ok { if !ok {
// intermediate key is a value // intermediate key is a value
// => replace with a new map // => replace with a new map
m3 = make(map[string]interface{}) m3 = make(map[string]any)
m[k] = m3 m[k] = m3
} }
// continue search from here // 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 // flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in the main package. // Code is based on the function with the same name in the main package.
// TODO: move it to a common place // 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 { if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten // prefix is shadowed => nothing more to flatten
return shadow return shadow
} }
if shadow == nil { 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 != "" { if prefix != "" {
prefix += delimiter prefix += delimiter
} }
for k, val := range m { for k, val := range m {
fullKey := prefix + k fullKey := prefix + k
switch val := val.(type) { switch val := val.(type) {
case map[string]interface{}: case map[string]any:
m2 = val m2 = val
case map[interface{}]interface{}: case map[any]any:
m2 = cast.ToStringMap(val) m2 = cast.ToStringMap(val)
default: default:
// immediate value // immediate value

View file

@ -7,11 +7,11 @@ import (
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding. // Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
type Codec struct{} 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? // TODO: expose prefix and indent in the Codec as setting?
return json.MarshalIndent(v, "", " ") 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) return json.Unmarshal(b, &v)
} }

View file

@ -29,20 +29,20 @@ const encoded = `{
}` }`
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
"nested_map": map[string]interface{}{ "nested_map": map[string]any{
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -68,7 +68,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(encoded), v) err := codec.Decode([]byte(encoded), v)
if err != nil { if err != nil {
@ -83,7 +83,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -7,10 +7,10 @@ import (
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding. // Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
type Codec struct{} 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) 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) return toml.Unmarshal(b, &v)
} }

View file

@ -39,20 +39,20 @@ list = ['item1', 'item2', 'item3']
` `
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
"nested_map": map[string]interface{}{ "nested_map": map[string]any{
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -78,7 +78,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -93,7 +93,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -5,10 +5,10 @@ import "gopkg.in/yaml.v3"
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding. // Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
type Codec struct{} 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) 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) return yaml.Unmarshal(b, &v)
} }

View file

@ -47,20 +47,20 @@ nested_map:
// //
// in case of YAML it's slightly different from Viper's internal representation // in case of YAML it's slightly different from Viper's internal representation
// (eg. map is decoded into a map with interface key) // (eg. map is decoded into a map with interface key)
var decoded = map[string]interface{}{ var decoded = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
"nested_map": map[string]interface{}{ "nested_map": map[string]any{
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -70,20 +70,20 @@ var decoded = map[string]interface{}{
} }
// Viper's internal representation // Viper's internal representation
var data = map[string]interface{}{ var data = map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
}, },
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
}, },
"nested_map": map[string]interface{}{ "nested_map": map[string]any{
"map": map[string]interface{}{ "map": map[string]any{
"key": "value", "key": "value",
"list": []interface{}{ "list": []any{
"item1", "item1",
"item2", "item2",
"item3", "item3",
@ -109,7 +109,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) { t.Run("OK", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(original), v) err := codec.Decode([]byte(original), v)
if err != nil { if err != nil {
@ -124,7 +124,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) { t.Run("InvalidData", func(t *testing.T) {
codec := Codec{} codec := Codec{}
v := map[string]interface{}{} v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v) err := codec.Decode([]byte(`invalid data`), v)
if err == nil { if err == nil {

View file

@ -16,30 +16,30 @@ type Logger interface {
// //
// Even more fine-grained information than Debug events. // Even more fine-grained information than Debug events.
// Loggers not supporting this level should fall back to Debug. // 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. // Debug logs a Debug event.
// //
// A verbose series of information events. // A verbose series of information events.
// They are useful when debugging the system. // They are useful when debugging the system.
Debug(msg string, keyvals ...interface{}) Debug(msg string, keyvals ...any)
// Info logs an Info event. // Info logs an Info event.
// //
// General information about what's happening inside the system. // 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. // Warn logs a Warn(ing) event.
// //
// Non-critical events that should be looked at. // Non-critical events that should be looked at.
Warn(msg string, keyvals ...interface{}) Warn(msg string, keyvals ...any)
// Error logs an Error event. // Error logs an Error event.
// //
// Critical events that require immediate attention. // Critical events that require immediate attention.
// Loggers commonly provide Fatal and Panic levels above Error level, // Loggers commonly provide Fatal and Panic levels above Error level,
// but exiting and panicking is out of scope for a logging library. // 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. // WithLogger sets a custom logger.

View file

@ -46,11 +46,11 @@ func TestNestedOverrides(t *testing.T) {
deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4) deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4)
// Case 4: key:value overridden by a map // 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} 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(4, v.Get("tom.size")) // "tom.size" should still be reachable
assert.Equal(10, v.Get("tom.age")) // new value should be there 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 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 = override(assert, "tom.size", 4, "tom", map[string]any{"age": 10})
assert.Nil(v.Get("tom.size")) assert.Nil(v.Get("tom.size"))
assert.Equal(10, v.Get("tom.age")) assert.Equal(10, v.Get("tom.age"))
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) 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) 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) 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 // After each assignment, the value is checked, retrieved both by its full path
// and by its key sequence (successive maps). // 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() v := New()
firstKeys := strings.Split(firstPath, v.keyDelim) firstKeys := strings.Split(firstPath, v.keyDelim)
if assert == nil || 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 // 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 // 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 || if assert == nil || v == nil ||
len(keys) == 0 || len(keys[0]) == 0 { len(keys) == 0 || len(keys[0]) == 0 {
return return
} }
// init // init
var val interface{} var val any
var ms string var ms string
switch l { switch l {
case defaultLayer: case defaultLayer:
@ -147,22 +147,22 @@ func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string,
} }
// loop through map // loop through map
var m map[string]interface{} var m map[string]any
err := false err := false
for _, k := range keys { for _, k := range keys {
if val == nil { 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 return
} }
// deep scan of the map to get the final value // deep scan of the map to get the final value
switch val := val.(type) { switch val := val.(type) {
case map[interface{}]interface{}: case map[any]any:
m = cast.ToStringMap(val) m = cast.ToStringMap(val)
case map[string]interface{}: case map[string]any:
m = val m = val
default: 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 return
} }
ms = ms + "[\"" + k + "\"]" ms = ms + "[\"" + k + "\"]"

36
util.go
View file

@ -39,11 +39,11 @@ func (pe ConfigParseError) Unwrap() error {
// toCaseInsensitiveValue checks if the value is a map; // toCaseInsensitiveValue checks if the value is a map;
// if so, create a copy and lower-case the keys recursively. // 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) { switch v := value.(type) {
case map[interface{}]interface{}: case map[any]any:
value = copyAndInsensitiviseMap(cast.ToStringMap(v)) value = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}: case map[string]any:
value = copyAndInsensitiviseMap(v) value = copyAndInsensitiviseMap(v)
} }
@ -52,15 +52,15 @@ func toCaseInsensitiveValue(value interface{}) interface{} {
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of // copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
// any map it makes case insensitive. // any map it makes case insensitive.
func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} { func copyAndInsensitiviseMap(m map[string]any) map[string]any {
nm := make(map[string]interface{}) nm := make(map[string]any)
for key, val := range m { for key, val := range m {
lkey := strings.ToLower(key) lkey := strings.ToLower(key)
switch v := val.(type) { switch v := val.(type) {
case map[interface{}]interface{}: case map[any]any:
nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v)) nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}: case map[string]any:
nm[lkey] = copyAndInsensitiviseMap(v) nm[lkey] = copyAndInsensitiviseMap(v)
default: default:
nm[lkey] = v nm[lkey] = v
@ -70,23 +70,23 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
return nm return nm
} }
func insensitiviseVal(val interface{}) interface{} { func insensitiviseVal(val any) any {
switch v := val.(type) { switch v := val.(type) {
case map[interface{}]interface{}: case map[any]any:
// nested map: cast and recursively insensitivise // nested map: cast and recursively insensitivise
val = cast.ToStringMap(val) val = cast.ToStringMap(val)
insensitiviseMap(val.(map[string]interface{})) insensitiviseMap(val.(map[string]any))
case map[string]interface{}: case map[string]any:
// nested map: recursively insensitivise // nested map: recursively insensitivise
insensitiviseMap(v) insensitiviseMap(v)
case []interface{}: case []any:
// nested array: recursively insensitivise // nested array: recursively insensitivise
insensitiveArray(v) insensitiveArray(v)
} }
return val return val
} }
func insensitiviseMap(m map[string]interface{}) { func insensitiviseMap(m map[string]any) {
for key, val := range m { for key, val := range m {
val = insensitiviseVal(val) val = insensitiviseVal(val)
lower := strings.ToLower(key) 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 { for i, val := range a {
a[i] = insensitiviseVal(val) 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, // 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: // a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified! // 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 { for _, k := range path {
m2, ok := m[k] m2, ok := m[k]
if !ok { if !ok {
// intermediate key does not exist // intermediate key does not exist
// => create it and continue from there // => create it and continue from there
m3 := make(map[string]interface{}) m3 := make(map[string]any)
m[k] = m3 m[k] = m3
m = m3 m = m3
continue continue
} }
m3, ok := m2.(map[string]interface{}) m3, ok := m2.(map[string]any)
if !ok { if !ok {
// intermediate key is a value // intermediate key is a value
// => replace with a new map // => replace with a new map
m3 = make(map[string]interface{}) m3 = make(map[string]any)
m[k] = m3 m[k] = m3
} }
// continue search from here // continue search from here

View file

@ -21,16 +21,16 @@ import (
func TestCopyAndInsensitiviseMap(t *testing.T) { func TestCopyAndInsensitiviseMap(t *testing.T) {
var ( var (
given = map[string]interface{}{ given = map[string]any{
"Foo": 32, "Foo": 32,
"Bar": map[interface{}]interface{}{ "Bar": map[any]any{
"ABc": "A", "ABc": "A",
"cDE": "B", "cDE": "B",
}, },
} }
expected = map[string]interface{}{ expected = map[string]any{
"foo": 32, "foo": 32,
"bar": map[string]interface{}{ "bar": map[string]any{
"abc": "A", "abc": "A",
"cde": "B", "cde": "B",
}, },
@ -51,7 +51,7 @@ func TestCopyAndInsensitiviseMap(t *testing.T) {
t.Fatal("Input map changed") t.Fatal("Input map changed")
} }
m := given["Bar"].(map[interface{}]interface{}) m := given["Bar"].(map[any]any)
if _, ok := m["ABc"]; !ok { if _, ok := m["ABc"]; !ok {
t.Fatal("Input map changed") t.Fatal("Input map changed")
} }

190
viper.go
View file

@ -207,10 +207,10 @@ type Viper struct {
allowEmptyEnv bool allowEmptyEnv bool
parents []string parents []string
config map[string]interface{} config map[string]any
override map[string]interface{} override map[string]any
defaults map[string]interface{} defaults map[string]any
kvstore map[string]interface{} kvstore map[string]any
pflags map[string]FlagValue pflags map[string]FlagValue
env map[string][]string env map[string][]string
aliases map[string]string aliases map[string]string
@ -232,11 +232,11 @@ func New() *Viper {
v.configName = "config" v.configName = "config"
v.configPermissions = os.FileMode(0o644) v.configPermissions = os.FileMode(0o644)
v.fs = afero.NewOsFs() v.fs = afero.NewOsFs()
v.config = make(map[string]interface{}) v.config = make(map[string]any)
v.parents = []string{} v.parents = []string{}
v.override = make(map[string]interface{}) v.override = make(map[string]any)
v.defaults = make(map[string]interface{}) v.defaults = make(map[string]any)
v.kvstore = make(map[string]interface{}) v.kvstore = make(map[string]any)
v.pflags = make(map[string]FlagValue) v.pflags = make(map[string]FlagValue)
v.env = make(map[string][]string) v.env = make(map[string][]string)
v.aliases = 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. // searchMap recursively searches for a value for path in source map.
// Returns nil if not found. // Returns nil if not found.
// Note: This assumes that the path entries and map keys are lower cased. // 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 { if len(path) == 0 {
return source return source
} }
@ -674,9 +674,9 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
// Nested case // Nested case
switch next := next.(type) { switch next := next.(type) {
case map[interface{}]interface{}: case map[any]any:
return v.searchMap(cast.ToStringMap(next), path[1:]) 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 // Type assertion is safe here since it is only reached
// if the type of `next` is the same as the type being asserted // if the type of `next` is the same as the type being asserted
return v.searchMap(next, path[1:]) return v.searchMap(next, path[1:])
@ -699,7 +699,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
// in their keys). // in their keys).
// //
// Note: This assumes that the path entries and map keys are lower cased. // 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 { if len(path) == 0 {
return source return source
} }
@ -708,11 +708,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin
for i := len(path); i > 0; i-- { for i := len(path); i > 0; i-- {
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim)) prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
var val interface{} var val any
switch sourceIndexable := source.(type) { switch sourceIndexable := source.(type) {
case []interface{}: case []any:
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path) val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
case map[string]interface{}: case map[string]any:
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path) val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
} }
if val != nil { 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 // This function is part of the searchIndexableWithPathPrefixes recurring search and
// should not be called directly from functions other than searchIndexableWithPathPrefixes. // should not be called directly from functions other than searchIndexableWithPathPrefixes.
func (v *Viper) searchSliceWithPathPrefixes( func (v *Viper) searchSliceWithPathPrefixes(
sourceSlice []interface{}, sourceSlice []any,
prefixKey string, prefixKey string,
pathIndex int, pathIndex int,
path []string, path []string,
) interface{} { ) any {
// if the prefixKey is not a number or it is out of bounds of the slice // if the prefixKey is not a number or it is out of bounds of the slice
index, err := strconv.Atoi(prefixKey) index, err := strconv.Atoi(prefixKey)
if err != nil || len(sourceSlice) <= index { if err != nil || len(sourceSlice) <= index {
@ -748,9 +748,9 @@ func (v *Viper) searchSliceWithPathPrefixes(
} }
switch n := next.(type) { switch n := next.(type) {
case map[interface{}]interface{}: case map[any]any:
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:]) return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
case map[string]interface{}, []interface{}: case map[string]any, []any:
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:]) return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
default: default:
// got a value but nested key expected, do nothing and look for next prefix // 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 // This function is part of the searchIndexableWithPathPrefixes recurring search and
// should not be called directly from functions other than searchIndexableWithPathPrefixes. // should not be called directly from functions other than searchIndexableWithPathPrefixes.
func (v *Viper) searchMapWithPathPrefixes( func (v *Viper) searchMapWithPathPrefixes(
sourceMap map[string]interface{}, sourceMap map[string]any,
prefixKey string, prefixKey string,
pathIndex int, pathIndex int,
path []string, path []string,
) interface{} { ) any {
next, ok := sourceMap[prefixKey] next, ok := sourceMap[prefixKey]
if !ok { if !ok {
return nil return nil
@ -782,9 +782,9 @@ func (v *Viper) searchMapWithPathPrefixes(
// Nested case // Nested case
switch n := next.(type) { switch n := next.(type) {
case map[interface{}]interface{}: case map[any]any:
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:]) return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
case map[string]interface{}, []interface{}: case map[string]any, []any:
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:]) return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
default: default:
// got a value but nested key expected, do nothing and look for next prefix // 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” // e.g., if "foo.bar" has a value in the given map, it “shadows”
// //
// "foo.bar.baz" in a lower-priority map // "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]any) string {
var parentVal interface{} var parentVal any
for i := 1; i < len(path); i++ { for i := 1; i < len(path); i++ {
parentVal = v.searchMap(m, path[0:i]) parentVal = v.searchMap(m, path[0:i])
if parentVal == nil { if parentVal == nil {
@ -808,9 +808,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
return "" return ""
} }
switch parentVal.(type) { switch parentVal.(type) {
case map[interface{}]interface{}: case map[any]any:
continue continue
case map[string]interface{}: case map[string]any:
continue continue
default: default:
// parentVal is a regular value which shadows "path" // 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” // e.g., if "foo.bar" has a value in the given map, it “shadows”
// //
// "foo.bar.baz" in a lower-priority map // "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 // unify input map
var m map[string]interface{} var m map[string]any
switch mi.(type) { switch mi.(type) {
case map[string]string, map[string]FlagValue: case map[string]string, map[string]FlagValue:
m = cast.ToStringMap(mi) m = cast.ToStringMap(mi)
@ -894,9 +894,9 @@ func GetViper() *Viper {
// override, flag, env, config file, key/value store, default // override, flag, env, config file, key/value store, default
// //
// Get returns an interface. For a specific value use one of the Get____ methods. // 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) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey, true) val := v.find(lcaseKey, true)
if val == nil { 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. // 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)) 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. // 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...) 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...)) return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...))
} }
// Unmarshal unmarshals the config into a Struct. Make sure that the tags // Unmarshal unmarshals the config into a Struct. Make sure that the tags
// on the fields of the structure are properly set. // 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...) 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...)) return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
} }
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support // defaultDecoderConfig returns default mapstructure.DecoderConfig with support
// of time.Duration values & string slices // 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{ c := &mapstructure.DecoderConfig{
Metadata: nil, Metadata: nil,
Result: output, Result: output,
@ -1133,7 +1133,7 @@ func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *maps
} }
// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality // 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) decoder, err := mapstructure.NewDecoder(config)
if err != nil { if err != nil {
return err 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 // UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
// in the destination struct. // in the destination struct.
func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error { func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
return v.UnmarshalExact(rawVal, opts...) 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 := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true config.ErrorUnused = true
@ -1244,9 +1244,9 @@ func (v *Viper) MustBindEnv(input ...string) {
// corresponds to a flag, the flag's default value is returned. // corresponds to a flag, the flag's default value is returned.
// //
// Note: this assumes a lower-cased key given. // 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 ( var (
val interface{} val any
exists bool exists bool
path = strings.Split(lcaseKey, v.keyDelim) path = strings.Split(lcaseKey, v.keyDelim)
nested = len(path) > 1 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 // 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 // alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
func stringToStringConv(val string) interface{} { func stringToStringConv(val string) any {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// An empty string would cause an empty map // An empty string would cause an empty map
if len(val) == 0 { if len(val) == 0 {
return map[string]interface{}{} return map[string]any{}
} }
r := csv.NewReader(strings.NewReader(val)) r := csv.NewReader(strings.NewReader(val))
ss, err := r.Read() ss, err := r.Read()
if err != nil { if err != nil {
return nil return nil
} }
out := make(map[string]interface{}, len(ss)) out := make(map[string]any, len(ss))
for _, pair := range ss { for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2) kv := strings.SplitN(pair, "=", 2)
if len(kv) != 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 // 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 // alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
func stringToIntConv(val string) interface{} { func stringToIntConv(val string) any {
val = strings.Trim(val, "[]") val = strings.Trim(val, "[]")
// An empty string would cause an empty map // An empty string would cause an empty map
if len(val) == 0 { if len(val) == 0 {
return map[string]interface{}{} return map[string]any{}
} }
ss := strings.Split(val, ",") ss := strings.Split(val, ",")
out := make(map[string]interface{}, len(ss)) out := make(map[string]any, len(ss))
for _, pair := range ss { for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2) kv := strings.SplitN(pair, "=", 2)
if len(kv) != 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 sets the default value for this key.
// SetDefault is case-insensitive for a key. // SetDefault is case-insensitive for a key.
// Default only used when no value is provided by the user via flag, config or ENV. // 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 // If alias passed in, then set the proper default
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
value = toCaseInsensitiveValue(value) value = toCaseInsensitiveValue(value)
@ -1564,9 +1564,9 @@ func (v *Viper) SetDefault(key string, value interface{}) {
// Set is case-insensitive for a key. // Set is case-insensitive for a key.
// Will be used instead of values obtained via // Will be used instead of values obtained via
// flags, config file, ENV, default, or key/value store. // 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 // If alias passed in, then set the proper override
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
value = toCaseInsensitiveValue(value) value = toCaseInsensitiveValue(value)
@ -1600,7 +1600,7 @@ func (v *Viper) ReadInConfig() error {
return err return err
} }
config := make(map[string]interface{}) config := make(map[string]any)
err = v.unmarshalReader(bytes.NewReader(file), config) err = v.unmarshalReader(bytes.NewReader(file), config)
if err != nil { if err != nil {
@ -1638,7 +1638,7 @@ func (v *Viper) MergeInConfig() error {
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
func (v *Viper) ReadConfig(in io.Reader) error { 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) 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 MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error { 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 { if err := v.unmarshalReader(in, cfg); err != nil {
return err 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. // MergeConfigMap merges the configuration from the map given with an existing config.
// Note that the map given may be modified. // 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 { if v.config == nil {
v.config = make(map[string]interface{}) v.config = make(map[string]any)
} }
insensitiviseMap(cfg) insensitiviseMap(cfg)
mergeMaps(cfg, v.config, nil) mergeMaps(cfg, v.config, nil)
@ -1724,7 +1724,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
return UnsupportedConfigError(configType) return UnsupportedConfigError(configType)
} }
if v.config == nil { 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 flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
if !force { if !force {
@ -1745,11 +1745,11 @@ func (v *Viper) writeConfig(filename string, force bool) error {
// Unmarshal a Reader into a map. // Unmarshal a Reader into a map.
// Should probably be an unexported function. // 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) 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 := new(bytes.Buffer)
buf.ReadFrom(in) buf.ReadFrom(in)
@ -1783,7 +1783,7 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
return nil return nil
} }
func keyExists(k string, m map[string]interface{}) string { func keyExists(k string, m map[string]any) string {
lk := strings.ToLower(k) lk := strings.ToLower(k)
for mk := range m { for mk := range m {
lmk := strings.ToLower(mk) lmk := strings.ToLower(mk)
@ -1795,33 +1795,33 @@ func keyExists(k string, m map[string]interface{}) string {
} }
func castToMapStringInterface( func castToMapStringInterface(
src map[interface{}]interface{}, src map[any]any,
) map[string]interface{} { ) map[string]any {
tgt := map[string]interface{}{} tgt := map[string]any{}
for k, v := range src { for k, v := range src {
tgt[fmt.Sprintf("%v", k)] = v tgt[fmt.Sprintf("%v", k)] = v
} }
return tgt return tgt
} }
func castMapStringSliceToMapInterface(src map[string][]string) map[string]interface{} { func castMapStringSliceToMapInterface(src map[string][]string) map[string]any {
tgt := map[string]interface{}{} tgt := map[string]any{}
for k, v := range src { for k, v := range src {
tgt[k] = v tgt[k] = v
} }
return tgt return tgt
} }
func castMapStringToMapInterface(src map[string]string) map[string]interface{} { func castMapStringToMapInterface(src map[string]string) map[string]any {
tgt := map[string]interface{}{} tgt := map[string]any{}
for k, v := range src { for k, v := range src {
tgt[k] = v tgt[k] = v
} }
return tgt return tgt
} }
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} { func castMapFlagToMapInterface(src map[string]FlagValue) map[string]any {
tgt := map[string]interface{}{} tgt := map[string]any{}
for k, v := range src { for k, v := range src {
tgt[k] = v 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 // 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 // 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 // deep. Both map types are supported as there is a go-yaml fork that uses
// `map[string]interface{}` instead. // `map[string]any` instead.
func mergeMaps( func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
src, tgt map[string]interface{}, itgt map[interface{}]interface{},
) {
for sk, sv := range src { for sk, sv := range src {
tk := keyExists(sk, tgt) tk := keyExists(sk, tgt)
if tk == "" { if tk == "" {
@ -1870,12 +1868,12 @@ func mergeMaps(
) )
switch ttv := tv.(type) { switch ttv := tv.(type) {
case map[interface{}]interface{}: case map[any]any:
v.logger.Debug("merging maps (must convert)") v.logger.Debug("merging maps (must convert)")
tsv, ok := sv.(map[interface{}]interface{}) tsv, ok := sv.(map[any]any)
if !ok { if !ok {
v.logger.Error( v.logger.Error(
"Could not cast sv to map[interface{}]interface{}", "Could not cast sv to map[any]any",
"key", sk, "key", sk,
"st", svType, "st", svType,
"tt", tvType, "tt", tvType,
@ -1888,12 +1886,12 @@ func mergeMaps(
ssv := castToMapStringInterface(tsv) ssv := castToMapStringInterface(tsv)
stv := castToMapStringInterface(ttv) stv := castToMapStringInterface(ttv)
mergeMaps(ssv, stv, ttv) mergeMaps(ssv, stv, ttv)
case map[string]interface{}: case map[string]any:
v.logger.Debug("merging maps") v.logger.Debug("merging maps")
tsv, ok := sv.(map[string]interface{}) tsv, ok := sv.(map[string]any)
if !ok { if !ok {
v.logger.Error( v.logger.Error(
"Could not cast sv to map[string]interface{}", "Could not cast sv to map[string]any",
"key", sk, "key", sk,
"st", svType, "st", svType,
"tt", tvType, "tt", tvType,
@ -1955,7 +1953,7 @@ func (v *Viper) getKeyValueConfig() error {
return RemoteConfigError("No Files Found") 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) reader, err := RemoteConfig.Get(provider)
if err != nil { if err != nil {
return nil, err return nil, err
@ -2004,7 +2002,7 @@ func (v *Viper) watchKeyValueConfig() error {
return RemoteConfigError("No Files Found") 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) reader, err := RemoteConfig.Watch(provider)
if err != nil { if err != nil {
return nil, err return nil, err
@ -2043,7 +2041,7 @@ func (v *Viper) AllKeys() []string {
// it is skipped. // it is skipped.
// //
// The resulting set of paths is merged to the given shadow set at the same time. // 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] { if shadow != nil && prefix != "" && shadow[prefix] {
// prefix is shadowed => nothing more to flatten // prefix is shadowed => nothing more to flatten
return shadow return shadow
@ -2052,16 +2050,16 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
shadow = make(map[string]bool) shadow = make(map[string]bool)
} }
var m2 map[string]interface{} var m2 map[string]any
if prefix != "" { if prefix != "" {
prefix += v.keyDelim prefix += v.keyDelim
} }
for k, val := range m { for k, val := range m {
fullKey := prefix + k fullKey := prefix + k
switch val := val.(type) { switch val := val.(type) {
case map[string]interface{}: case map[string]any:
m2 = val m2 = val
case map[interface{}]interface{}: case map[any]any:
m2 = cast.ToStringMap(val) m2 = cast.ToStringMap(val)
default: default:
// immediate value // 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 // mergeFlatMap merges the given maps, excluding values of the second map
// shadowed by values from the first 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 // scan keys
outer: outer:
for k := range m { for k := range m {
@ -2096,11 +2094,11 @@ outer:
return shadow return shadow
} }
// AllSettings merges all settings and returns them as a map[string]interface{}. // AllSettings merges all settings and returns them as a map[string]any.
func AllSettings() map[string]interface{} { return v.AllSettings() } func AllSettings() map[string]any { return v.AllSettings() }
func (v *Viper) AllSettings() map[string]interface{} { func (v *Viper) AllSettings() map[string]any {
m := map[string]interface{}{} m := map[string]any{}
// start from the list of keys, and construct the map one value at a time // start from the list of keys, and construct the map one value at a time
for _, k := range v.AllKeys() { for _, k := range v.AllKeys() {
value := v.Get(k) value := v.Get(k)

View file

@ -496,8 +496,8 @@ func TestUnmarshaling(t *testing.T) {
assert.False(t, InConfig("state")) assert.False(t, InConfig("state"))
assert.False(t, InConfig("clothing.hat")) assert.False(t, InConfig("clothing.hat"))
assert.Equal(t, "steve", Get("name")) assert.Equal(t, "steve", Get("name"))
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies")) assert.Equal(t, []any{"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, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, Get("clothing"))
assert.Equal(t, 35, Get("age")) assert.Equal(t, 35, Get("age"))
} }
@ -774,14 +774,14 @@ func TestAllKeys(t *testing.T) {
"name_dotenv", "name_dotenv",
} }
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
all := map[string]interface{}{ all := map[string]any{
"owner": map[string]interface{}{ "owner": map[string]any{
"organization": "MongoDB", "organization": "MongoDB",
"bio": "MongoDB Chief Developer Advocate & Hacker at Large", "bio": "MongoDB Chief Developer Advocate & Hacker at Large",
"dob": dob, "dob": dob,
}, },
"title": "TOML Example", "title": "TOML Example",
"author": map[string]interface{}{ "author": map[string]any{
"e-mail": "fake@localhost", "e-mail": "fake@localhost",
"github": "https://github.com/Unknown", "github": "https://github.com/Unknown",
"name": "Unknown", "name": "Unknown",
@ -789,28 +789,28 @@ func TestAllKeys(t *testing.T) {
}, },
"ppu": 0.55, "ppu": 0.55,
"eyes": "brown", "eyes": "brown",
"clothing": map[string]interface{}{ "clothing": map[string]any{
"trousers": "denim", "trousers": "denim",
"jacket": "leather", "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", "import_path": "gopkg.in/ini.v1",
"name": "ini", "name": "ini",
"version": "v1", "version": "v1",
}, },
"id": "0001", "id": "0001",
"batters": map[string]interface{}{ "batters": map[string]any{
"batter": []interface{}{ "batter": []any{
map[string]interface{}{"type": "Regular"}, map[string]any{"type": "Regular"},
map[string]interface{}{"type": "Chocolate"}, map[string]any{"type": "Chocolate"},
map[string]interface{}{"type": "Blueberry"}, map[string]any{"type": "Blueberry"},
map[string]interface{}{"type": "Devil's Food"}, map[string]any{"type": "Devil's Food"},
}, },
}, },
"hacker": true, "hacker": true,
"beard": true, "beard": true,
"hobbies": []interface{}{ "hobbies": []any{
"skateboarding", "skateboarding",
"snowboarding", "snowboarding",
"go", "go",
@ -822,13 +822,13 @@ func TestAllKeys(t *testing.T) {
"p_id": "0001", "p_id": "0001",
"p_ppu": "0.55", "p_ppu": "0.55",
"p_name": "Cake", "p_name": "Cake",
"p_batters": map[string]interface{}{ "p_batters": map[string]any{
"batter": map[string]interface{}{"type": "Regular"}, "batter": map[string]any{"type": "Regular"},
}, },
"p_type": "donut", "p_type": "donut",
"foos": []map[string]interface{}{ "foos": []map[string]any{
{ {
"foo": []map[string]interface{}{ "foo": []map[string]any{
{"key": 1}, {"key": 1},
{"key": 2}, {"key": 2},
{"key": 3}, {"key": 3},
@ -937,7 +937,7 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","), mapstructure.StringToSliceHookFunc(","),
// Custom Decode Hook Function // 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 { if rf != reflect.String || rt != reflect.Map {
return data, nil return data, nil
} }
@ -1328,38 +1328,38 @@ func TestFindsNestedKeys(t *testing.T) {
initConfigs() initConfigs()
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
Set("super", map[string]interface{}{ Set("super", map[string]any{
"deep": map[string]interface{}{ "deep": map[string]any{
"nested": "value", "nested": "value",
}, },
}) })
expected := map[string]interface{}{ expected := map[string]any{
"super": map[string]interface{}{ "super": map[string]any{
"deep": map[string]interface{}{ "deep": map[string]any{
"nested": "value", "nested": "value",
}, },
}, },
"super.deep": map[string]interface{}{ "super.deep": map[string]any{
"nested": "value", "nested": "value",
}, },
"super.deep.nested": "value", "super.deep.nested": "value",
"owner.organization": "MongoDB", "owner.organization": "MongoDB",
"batters.batter": []interface{}{ "batters.batter": []any{
map[string]interface{}{ map[string]any{
"type": "Regular", "type": "Regular",
}, },
map[string]interface{}{ map[string]any{
"type": "Chocolate", "type": "Chocolate",
}, },
map[string]interface{}{ map[string]any{
"type": "Blueberry", "type": "Blueberry",
}, },
map[string]interface{}{ map[string]any{
"type": "Devil's Food", "type": "Devil's Food",
}, },
}, },
"hobbies": []interface{}{ "hobbies": []any{
"skateboarding", "snowboarding", "go", "skateboarding", "snowboarding", "go",
}, },
"TITLE_DOTENV": "DotEnv Example", "TITLE_DOTENV": "DotEnv Example",
@ -1367,25 +1367,25 @@ func TestFindsNestedKeys(t *testing.T) {
"NAME_DOTENV": "Cake", "NAME_DOTENV": "Cake",
"title": "TOML Example", "title": "TOML Example",
"newkey": "remote", "newkey": "remote",
"batters": map[string]interface{}{ "batters": map[string]any{
"batter": []interface{}{ "batter": []any{
map[string]interface{}{ map[string]any{
"type": "Regular", "type": "Regular",
}, },
map[string]interface{}{ map[string]any{
"type": "Chocolate", "type": "Chocolate",
}, },
map[string]interface{}{ map[string]any{
"type": "Blueberry", "type": "Blueberry",
}, },
map[string]interface{}{ map[string]any{
"type": "Devil's Food", "type": "Devil's Food",
}, },
}, },
}, },
"eyes": "brown", "eyes": "brown",
"age": 35, "age": 35,
"owner": map[string]interface{}{ "owner": map[string]any{
"organization": "MongoDB", "organization": "MongoDB",
"bio": "MongoDB Chief Developer Advocate & Hacker at Large", "bio": "MongoDB Chief Developer Advocate & Hacker at Large",
"dob": dob, "dob": dob,
@ -1396,10 +1396,10 @@ func TestFindsNestedKeys(t *testing.T) {
"name": "Cake", "name": "Cake",
"hacker": true, "hacker": true,
"ppu": 0.55, "ppu": 0.55,
"clothing": map[string]interface{}{ "clothing": map[string]any{
"jacket": "leather", "jacket": "leather",
"trousers": "denim", "trousers": "denim",
"pants": map[string]interface{}{ "pants": map[string]any{
"size": "large", "size": "large",
}, },
}, },
@ -1408,9 +1408,9 @@ func TestFindsNestedKeys(t *testing.T) {
"clothing.trousers": "denim", "clothing.trousers": "denim",
"owner.dob": dob, "owner.dob": dob,
"beard": true, "beard": true,
"foos": []map[string]interface{}{ "foos": []map[string]any{
{ {
"foo": []map[string]interface{}{ "foo": []map[string]any{
{ {
"key": 1, "key": 1,
}, },
@ -1444,8 +1444,8 @@ func TestReadBufConfig(t *testing.T) {
assert.False(t, v.InConfig("state")) assert.False(t, v.InConfig("state"))
assert.False(t, v.InConfig("clothing.hat")) assert.False(t, v.InConfig("clothing.hat"))
assert.Equal(t, "steve", v.Get("name")) assert.Equal(t, "steve", v.Get("name"))
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies")) assert.Equal(t, []any{"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, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, v.Get("clothing"))
assert.Equal(t, 35, v.Get("age")) assert.Equal(t, 35, v.Get("age"))
} }
@ -2180,11 +2180,11 @@ func TestMergeConfigMap(t *testing.T) {
assert(37890) assert(37890)
update := map[string]interface{}{ update := map[string]any{
"Hello": map[string]interface{}{ "Hello": map[string]any{
"Pop": 1234, "Pop": 1234,
}, },
"World": map[interface{}]interface{}{ "World": map[any]any{
"Rock": 345, "Rock": 345,
}, },
} }
@ -2255,7 +2255,7 @@ clothing:
assert.Nil(t, Get("clothing.jacket.price")) assert.Nil(t, Get("clothing.jacket.price"))
assert.Equal(t, polyester, GetString("clothing.shirt")) 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, "leather", clothingSettings["jacket"])
assert.Equal(t, polyester, clothingSettings["shirt"]) assert.Equal(t, polyester, clothingSettings["shirt"])
} }
@ -2267,7 +2267,7 @@ func TestDotParameter(t *testing.T) {
unmarshalReader(r, v.config) unmarshalReader(r, v.config)
actual := Get("batters.batter") actual := Get("batters.batter")
expected := []interface{}{map[string]interface{}{"type": "Small"}} expected := []any{map[string]any{"type": "Small"}}
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }
@ -2318,17 +2318,17 @@ R = 6
func TestCaseInsensitiveSet(t *testing.T) { func TestCaseInsensitiveSet(t *testing.T) {
Reset() Reset()
m1 := map[string]interface{}{ m1 := map[string]any{
"Foo": 32, "Foo": 32,
"Bar": map[interface{}]interface{}{ "Bar": map[any]any{
"ABc": "A", "ABc": "A",
"cDE": "B", "cDE": "B",
}, },
} }
m2 := map[string]interface{}{ m2 := map[string]any{
"Foo": 52, "Foo": 52,
"Bar": map[interface{}]interface{}{ "Bar": map[any]any{
"bCd": "A", "bCd": "A",
"eFG": "B", "eFG": "B",
}, },
@ -2559,13 +2559,13 @@ func TestKeyDelimiter(t *testing.T) {
err := v.unmarshalReader(r, v.config) err := v.unmarshalReader(r, v.config)
require.NoError(t, err) require.NoError(t, err)
values := map[string]interface{}{ values := map[string]any{
"image": map[string]interface{}{ "image": map[string]any{
"repository": "someImage", "repository": "someImage",
"tag": "1.0.0", "tag": "1.0.0",
}, },
"ingress": map[string]interface{}{ "ingress": map[string]any{
"annotations": map[string]interface{}{ "annotations": map[string]any{
"traefik.frontend.rule.type": "PathPrefix", "traefik.frontend.rule.type": "PathPrefix",
"traefik.ingress.kubernetes.io/ssl-redirect": "true", "traefik.ingress.kubernetes.io/ssl-redirect": "true",
}, },
@ -2579,13 +2579,13 @@ func TestKeyDelimiter(t *testing.T) {
type config struct { type config struct {
Charts struct { Charts struct {
Values map[string]interface{} Values map[string]any
} }
} }
expected := config{ expected := config{
Charts: struct { Charts: struct {
Values map[string]interface{} Values map[string]any
}{ }{
Values: values, Values: values,
}, },