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:
juancwu 2026-04-27 20:35:51 +00:00
commit c4ebd80669
15 changed files with 941 additions and 0 deletions

33
json.go Normal file
View file

@ -0,0 +1,33 @@
package conf
import (
"encoding/json"
"io"
"os"
"git.juancwu.dev/juancwu/errx"
)
// JSONFile loads a JSON object and exposes it as a flat key->string Source.
func JSONFile(path string) (Source, error) {
const op = "conf.JSONFile"
f, err := os.Open(path)
if err != nil {
return nil, errx.Wrapf(op, err, "open %s", path)
}
defer f.Close()
return JSONReader(f)
}
// JSONReader is JSONFile for an arbitrary reader.
func JSONReader(r io.Reader) (Source, error) {
const op = "conf.JSONReader"
var raw map[string]any
if err := json.NewDecoder(r).Decode(&raw); err != nil {
if err == io.EOF {
return MapSource(nil), nil
}
return nil, errx.Wrap(op, err)
}
return MapSource(flatten(raw)), nil
}