Home

cfg @2d0ac7163fc5126251847c958793c75aea8c4ac9 - refs - log -
-
https://git.jolheiser.com/cfg.git
Convert between various configuration formats
cfg / cfg.go
- raw -
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package cfg

import (
	"encoding/json"
	"fmt"
	"strings"

	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/cue/format"
	"github.com/google/go-jsonnet"
	"github.com/pelletier/go-toml/v2"
	"github.com/philandstuff/dhall-golang/v6"
	"github.com/sblinch/kdl-go"
	"github.com/tailscale/hujson"
	"go.jolheiser.com/nixfig"
	"gopkg.in/yaml.v3"
)

// Encoding is a type of configuration encoding
type Encoding string

const (
	JSON    Encoding = "json"
	JSONC   Encoding = "jsonc"
	JSONNET Encoding = "jsonnet"
	YAML    Encoding = "yaml"
	TOML    Encoding = "toml"
	NIX     Encoding = "nix"
	DHALL   Encoding = "dhall"
	KDL     Encoding = "kdl"
	CUE     Encoding = "cue"
)

// Marshal takes data and encodes for an [Encoding]
func (e Encoding) Marshal(v any) ([]byte, error) {
	return Marshal(e, v)
}

// Unmarshal decodes data for an [Encoding]
func (e Encoding) Unmarshal(data []byte, v any) error {
	return Unmarshal(e, data, v)
}

// ParseEncoding parses a string into an [Encoding]
func ParseEncoding(s string) (Encoding, error) {
	switch strings.ToLower(s) {
	case "json":
		return JSON, nil
	case "jsonc":
		return JSONC, nil
	case "jsonnet":
		return JSONNET, nil
	case "yaml":
		return YAML, nil
	case "toml":
		return TOML, nil
	case "nix":
		return NIX, nil
	case "dhall":
		return DHALL, nil
	case "kdl":
		return KDL, nil
	case "cue":
		return CUE, nil
	default:
		return "", fmt.Errorf("unknown encoding %q", s)
	}
}

// Marshal is a top-level helper for encoding data
func Marshal(e Encoding, v any) ([]byte, error) {
	switch e {
	case JSON, JSONC:
		return json.MarshalIndent(v, "", "\t")
	case YAML:
		return yaml.Marshal(v)
	case TOML:
		return toml.Marshal(v)
	case NIX:
		if nixfig.Fmt != nil {
			return nixfig.MarshalFormat(v)
		}
		return nixfig.Marshal(v)
	case KDL:
		return kdl.Marshal(v)
	case CUE:
		return format.Node(cuecontext.New().Encode(v).Syntax(), format.Simplify())
	default:
		return nil, fmt.Errorf("unknown marshal format %q", e)
	}
}

// Unmarshal is a top-level helper for decoding data
func Unmarshal(e Encoding, data []byte, v any) error {
	switch e {
	case JSON, JSONC:
		b, err := hujson.Standardize(data)
		if err != nil {
			return err
		}
		return json.Unmarshal(b, v)
	case JSONNET:
		vm := jsonnet.MakeVM()
		data, err := vm.EvaluateAnonymousSnippet("cfg", string(data))
		if err != nil {
			return err
		}
		return json.Unmarshal([]byte(data), v)
	case YAML:
		return yaml.Unmarshal(data, v)
	case TOML:
		return toml.Unmarshal(data, v)
	case NIX:
		return nixfig.Unmarshal(data, v)
	case DHALL:
		return dhall.Unmarshal(data, v)
	case KDL:
		return kdl.Unmarshal(data, v)
	case CUE:
		ctx := cuecontext.New()
		cueData := ctx.CompileBytes(data)
		return cueData.Decode(v)
	default:
		return fmt.Errorf("unknown unmarshal format %q", e)

	}
}