Add reflective struct-tag config loader
Implements conf.Load to populate tagged structs from a chain of Sources (env, .env, YAML/JSON/TOML, custom). Supports default values, slice separators, nested structs, pointer fields, and a Validator hook. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3c806e6803
commit
c4ebd80669
15 changed files with 941 additions and 0 deletions
44
flatten.go
Normal file
44
flatten.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// flatten walks a nested map[string]any (as produced by yaml/json/toml decoders)
|
||||
// and returns a flat key->string map. Keys are uppercased and joined with "_".
|
||||
// Scalar values are stringified via fmt.Sprint. Slices are joined with ",".
|
||||
func flatten(in map[string]any) map[string]string {
|
||||
out := map[string]string{}
|
||||
flattenInto(out, "", in)
|
||||
return out
|
||||
}
|
||||
|
||||
func flattenInto(out map[string]string, prefix string, in map[string]any) {
|
||||
for k, v := range in {
|
||||
key := strings.ToUpper(k)
|
||||
if prefix != "" {
|
||||
key = prefix + "_" + key
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case map[string]any:
|
||||
flattenInto(out, key, x)
|
||||
case map[any]any: // yaml.v3 with non-string keys
|
||||
m := make(map[string]any, len(x))
|
||||
for kk, vv := range x {
|
||||
m[fmt.Sprint(kk)] = vv
|
||||
}
|
||||
flattenInto(out, key, m)
|
||||
case []any:
|
||||
parts := make([]string, len(x))
|
||||
for i, e := range x {
|
||||
parts[i] = fmt.Sprint(e)
|
||||
}
|
||||
out[key] = strings.Join(parts, ",")
|
||||
case nil:
|
||||
// skip
|
||||
default:
|
||||
out[key] = fmt.Sprint(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue