Files
AbstractWizard/config/parser.go
2026-02-15 08:49:27 +00:00

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
}