diff --git a/CHANGELOG.md b/CHANGELOG.md index e516cc36..76b8bc18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [1.2.0] - 2024-06-10 + +### Changed + +- [Breaking] The map key is case insensitive now. If you would like to keep it case sensitive. + please add konf.WithMapKeyCaseSensitive option (#365). + ## [1.1.1] - 2024-05-02 ### Fixed diff --git a/config.go b/config.go index 2cc0ec6a..01d059a0 100644 --- a/config.go +++ b/config.go @@ -28,11 +28,12 @@ type Config struct { nocopy internal.NoCopy[Config] // Options. - caseSensitive bool - delimiter string - logger *slog.Logger - onStatus func(loader Loader, changed bool, err error) - converter convert.Converter + caseSensitive bool + mapKeyCaseSensitive bool + delimiter string + logger *slog.Logger + onStatus func(loader Loader, changed bool, err error) + converter convert.Converter // Loaded configuration. values map[string]any @@ -162,7 +163,7 @@ func (c *Config) delim() string { func (c *Config) transformKeys(m map[string]any) { if !c.caseSensitive { - maps.TransformKeys(m, strings.ToLower) + maps.TransformKeys(m, strings.ToLower, c.mapKeyCaseSensitive) } } diff --git a/config_test.go b/config_test.go index 39592209..c7f8b896 100644 --- a/config_test.go +++ b/config_test.go @@ -86,6 +86,16 @@ func TestConfig_Unmarshal(t *testing.T) { { description: "config for map", loaders: []konf.Loader{mapLoader{"Config": "struct"}}, + assert: func(config *konf.Config) { + var value map[string]string + assert.NoError(t, config.Unmarshal("", &value)) + assert.Equal(t, "struct", value["config"]) + }, + }, + { + description: "config for map (case sensitive)", + loaders: []konf.Loader{mapLoader{"Config": "struct"}}, + opts: []konf.Option{konf.WithMapKeyCaseSensitive()}, assert: func(config *konf.Config) { var value map[string]string assert.NoError(t, config.Unmarshal("", &value)) diff --git a/internal/maps/transform.go b/internal/maps/transform.go index 711cc652..ed83375f 100644 --- a/internal/maps/transform.go +++ b/internal/maps/transform.go @@ -3,18 +3,22 @@ package maps -func TransformKeys(src map[string]interface{}, keyMap func(string) string) { +func TransformKeys(src map[string]interface{}, keyMap func(string) string, mapKeyCaseSensitive bool) { if src == nil || keyMap == nil { return } for key, value := range src { if m, ok := value.(map[string]interface{}); ok { - TransformKeys(m, keyMap) + TransformKeys(m, keyMap, mapKeyCaseSensitive) } newKey := keyMap(key) if newKey != key { delete(src, key) - src[newKey] = Pack(key, value) + if mapKeyCaseSensitive { + src[newKey] = Pack(key, value) + } else { + src[newKey] = value + } } } } diff --git a/internal/maps/transform_test.go b/internal/maps/transform_test.go index e3120f3a..f70ffbb9 100644 --- a/internal/maps/transform_test.go +++ b/internal/maps/transform_test.go @@ -15,10 +15,11 @@ func TestTransformKeys(t *testing.T) { t.Parallel() testcases := []struct { - description string - src map[string]any - keyMap func(string) string - expected map[string]any + description string + src map[string]any + keyMap func(string) string + mapKeyCaseSensitive bool + expected map[string]any }{ { description: "nil map", @@ -33,7 +34,14 @@ func TestTransformKeys(t *testing.T) { description: "transform keys", src: map[string]any{"A": map[string]any{"X": 1, "y": 2}}, keyMap: strings.ToLower, - expected: map[string]any{"a": maps.Pack("A", map[string]any{"x": maps.Pack("X", 1), "y": 2})}, + expected: map[string]any{"a": map[string]any{"x": 1, "y": 2}}, + }, + { + description: "transform keys", + src: map[string]any{"A": map[string]any{"X": 1, "y": 2}}, + keyMap: strings.ToLower, + mapKeyCaseSensitive: true, + expected: map[string]any{"a": maps.Pack("A", map[string]any{"x": maps.Pack("X", 1), "y": 2})}, }, } @@ -42,7 +50,7 @@ func TestTransformKeys(t *testing.T) { t.Run(tc.description, func(t *testing.T) { t.Parallel() - maps.TransformKeys(tc.src, tc.keyMap) + maps.TransformKeys(tc.src, tc.keyMap, tc.mapKeyCaseSensitive) assert.Equal(t, tc.expected, tc.src) }) } diff --git a/option.go b/option.go index b0c135bf..a532f3f4 100644 --- a/option.go +++ b/option.go @@ -68,6 +68,13 @@ func WithCaseSensitive() Option { } } +// WithMapKeyCaseSensitive enables the case sensitivity of the map keys. +func WithMapKeyCaseSensitive() Option { + return func(options *options) { + options.mapKeyCaseSensitive = true + } +} + type ( // Option configures a Config with specific options. Option func(*options)