diff --git a/provider/env/env.go b/provider/env/env.go index 9d1e2ae3..deec75fc 100644 --- a/provider/env/env.go +++ b/provider/env/env.go @@ -48,7 +48,10 @@ func (e Env) Load() (map[string]any, error) { // The environment variable with empty value is treated as unset. continue } - maps.Insert(values, e.splitter(key), value) + + if keys := e.splitter(key); len(keys) > 1 || len(keys) == 1 && keys[0] != "" { + maps.Insert(values, keys, value) + } } } diff --git a/provider/env/env_test.go b/provider/env/env_test.go index 1a986350..e838a050 100644 --- a/provider/env/env_test.go +++ b/provider/env/env_test.go @@ -42,6 +42,22 @@ func TestEnv_Load(t *testing.T) { }, }, }, + { + description: "with nil splitter", + opts: []env.Option{ + env.WithPrefix("P."), + env.WithNameSplitter(func(string) []string { return nil }), + }, + expected: map[string]any{}, + }, + { + description: "with empty splitter", + opts: []env.Option{ + env.WithPrefix("P."), + env.WithNameSplitter(func(string) []string { return []string{""} }), + }, + expected: map[string]any{}, + }, } t.Setenv("P_K", "v") diff --git a/provider/env/option.go b/provider/env/option.go index a5a6bc82..cf341e41 100644 --- a/provider/env/option.go +++ b/provider/env/option.go @@ -31,6 +31,7 @@ func WithDelimiter(delimiter string) Option { } // WithNameSplitter provides the function used to split environment variable names into nested keys. +// If it returns an nil/[]string{}/[]string{""}, the variable will be ignored. // // For example, with the default splitter, an environment variable name like "PARENT_CHILD_KEY" // would be split into "PARENT", "CHILD", and "KEY". diff --git a/provider/flag/flag.go b/provider/flag/flag.go index 4376f095..2fd73b4e 100644 --- a/provider/flag/flag.go +++ b/provider/flag/flag.go @@ -73,6 +73,10 @@ func (f Flag) Load() (map[string]any, error) { } keys := f.splitter(flag.Name) + if len(keys) == 0 || len(keys) == 1 && keys[0] == "" { + return + } + val := flag.Value.String() // Skip zero default value to avoid overriding values set by other loader. if val == flag.DefValue && (f.konf.Exists(keys) || isZeroDefValue(flag)) { diff --git a/provider/flag/flag_test.go b/provider/flag/flag_test.go index 47881259..3d64d9a9 100644 --- a/provider/flag/flag_test.go +++ b/provider/flag/flag_test.go @@ -52,6 +52,22 @@ func TestFlag_Load(t *testing.T) { }, }, }, + { + description: "with nil splitter", + opts: []kflag.Option{ + kflag.WithPrefix("p_"), + kflag.WithNameSplitter(func(string) []string { return nil }), + }, + expected: map[string]any{}, + }, + { + description: "with empty splitter", + opts: []kflag.Option{ + kflag.WithPrefix("p_"), + kflag.WithNameSplitter(func(string) []string { return []string{""} }), + }, + expected: map[string]any{}, + }, { description: "with prefix", opts: []kflag.Option{kflag.WithPrefix("p.")}, diff --git a/provider/flag/option.go b/provider/flag/option.go index 137f564b..2514c452 100644 --- a/provider/flag/option.go +++ b/provider/flag/option.go @@ -43,6 +43,7 @@ func WithDelimiter(delimiter string) Option { } // WithNameSplitter provides the function used to split environment variable names into nested keys. +// If it returns an nil/[]string{}/[]string{""}, the variable will be ignored. // // For example, with the default splitter, an flag name like "parent.child.key" // would be split into "parent", "child", and "key". diff --git a/provider/pflag/option.go b/provider/pflag/option.go index e0fc5fff..3ad4a9b2 100644 --- a/provider/pflag/option.go +++ b/provider/pflag/option.go @@ -44,6 +44,7 @@ func WithDelimiter(delimiter string) Option { } // WithNameSplitter provides the function used to split environment variable names into nested keys. +// If it returns an nil/[]string{}/[]string{""}, the variable will be ignored. // // For example, with the default splitter, an flag name like "parent.child.key" // // would be split into "parent", "child", and "key". diff --git a/provider/pflag/pflag.go b/provider/pflag/pflag.go index d84ac952..b278bc70 100644 --- a/provider/pflag/pflag.go +++ b/provider/pflag/pflag.go @@ -77,6 +77,10 @@ func (f PFlag) Load() (map[string]any, error) { } keys := f.splitter(flag.Name) + if len(keys) == 0 || len(keys) == 1 && keys[0] == "" { + return + } + val := f.flagVal(flag) // Skip zero default value to avoid overriding values set by other loader. if !flag.Changed && (f.konf.Exists(keys) || reflect.ValueOf(val).IsZero()) { diff --git a/provider/pflag/pflag_test.go b/provider/pflag/pflag_test.go index eeba96a1..22aee58a 100644 --- a/provider/pflag/pflag_test.go +++ b/provider/pflag/pflag_test.go @@ -56,6 +56,22 @@ func TestPFlag_Load(t *testing.T) { }, }, }, + { + description: "with nil splitter", + opts: []kflag.Option{ + kflag.WithPrefix("p_"), + kflag.WithNameSplitter(func(string) []string { return nil }), + }, + expected: map[string]any{}, + }, + { + description: "with empty splitter", + opts: []kflag.Option{ + kflag.WithPrefix("p_"), + kflag.WithNameSplitter(func(string) []string { return []string{""} }), + }, + expected: map[string]any{}, + }, { description: "with prefix", opts: []kflag.Option{kflag.WithPrefix("p.")},