84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Format represents a config file format.
|
|
type Format int
|
|
|
|
const (
|
|
FormatJSON Format = iota
|
|
FormatYAML
|
|
)
|
|
|
|
// DetectFormat returns the format based on file extension.
|
|
func DetectFormat(path string) (Format, error) {
|
|
ext := strings.ToLower(filepath.Ext(path))
|
|
switch ext {
|
|
case ".json":
|
|
return FormatJSON, nil
|
|
case ".yaml", ".yml":
|
|
return FormatYAML, nil
|
|
default:
|
|
return 0, fmt.Errorf("unsupported format: %s", ext)
|
|
}
|
|
}
|
|
|
|
// Parse deserializes raw bytes into a map based on the given format.
|
|
func Parse(data []byte, format Format) (map[string]any, error) {
|
|
var result map[string]any
|
|
switch format {
|
|
case FormatJSON:
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
return nil, fmt.Errorf("invalid JSON: %w", err)
|
|
}
|
|
case FormatYAML:
|
|
if err := yaml.Unmarshal(data, &result); err != nil {
|
|
return nil, fmt.Errorf("invalid YAML: %w", err)
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unknown format")
|
|
}
|
|
if result == nil {
|
|
result = make(map[string]any)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// Serialize converts a map back to bytes in the given format.
|
|
func Serialize(data map[string]any, format Format) ([]byte, error) {
|
|
switch format {
|
|
case FormatJSON:
|
|
return json.MarshalIndent(data, "", " ")
|
|
case FormatYAML:
|
|
return yaml.Marshal(data)
|
|
default:
|
|
return nil, fmt.Errorf("unknown format")
|
|
}
|
|
}
|
|
|
|
// DeepMerge merges src into dst recursively. Values in src override those in dst.
|
|
// Nested maps are merged; all other types are replaced.
|
|
func DeepMerge(dst, src map[string]any) map[string]any {
|
|
out := make(map[string]any, len(dst))
|
|
for k, v := range dst {
|
|
out[k] = v
|
|
}
|
|
for k, v := range src {
|
|
if srcMap, ok := v.(map[string]any); ok {
|
|
if dstMap, ok := out[k].(map[string]any); ok {
|
|
out[k] = DeepMerge(dstMap, srcMap)
|
|
continue
|
|
}
|
|
}
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|