package ffhujson import ( "bytes" "encoding/json" "fmt" "io" "github.com/tailscale/hujson" ) // Parser is a helper function that uses a default ParseConfig. func Parser(r io.Reader, set func(name, value string) error) error { return (&ParseConfig{}).Parse(r, set) } // ParseConfig collects parameters for the config file parser. type ParseConfig struct { // Delimiter is used when concatenating nested node keys into a flag name. // The default delimiter is ".". Delimiter string } // Parse a document from the provided io.Reader, using the provided set // function to set flag values. Flag names are derived from the node names and // their key/value pairs. func (pc *ParseConfig) Parse(r io.Reader, set func(name, value string) error) error { if pc.Delimiter == "" { pc.Delimiter = "." } data, err := io.ReadAll(r) if err != nil { return err } data, err = hujson.Standardize(data) if err != nil { return err } d := json.NewDecoder(bytes.NewBuffer(data)) d.UseNumber() // required for stringifying values var m map[string]interface{} if err := d.Decode(&m); err != nil { return ParseError{Inner: err} } if err := traverseMap(m, pc.Delimiter, set); err != nil { return ParseError{Inner: err} } return nil } // ParseError wraps all errors originating from the Parser. type ParseError struct { Inner error } // Error implenents the error interface. func (e ParseError) Error() string { return fmt.Sprintf("error parsing config: %v", e.Inner) } // Unwrap implements the errors.Wrapper interface, allowing errors.Is and // errors.As to work with ParseErrors. func (e ParseError) Unwrap() error { return e.Inner }