File: toml_encoder.go

package info (click to toggle)
dasel 2.8.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,844 kB
  • sloc: sh: 53; python: 21; makefile: 21; xml: 20
file content (99 lines) | stat: -rw-r--r-- 2,246 bytes parent folder | download
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
package dencoding

import (
	"bytes"
	"github.com/pelletier/go-toml/v2"
	"io"
)

// TOMLEncoder wraps a standard toml encoder to implement custom ordering logic.
type TOMLEncoder struct {
	encoder *toml.Encoder
	writer  io.Writer
	buffer  *bytes.Buffer
}

// NewTOMLEncoder returns a new dencoding TOMLEncoder.
func NewTOMLEncoder(w io.Writer, options ...TOMLEncoderOption) *TOMLEncoder {
	buffer := new(bytes.Buffer)
	tomlEncoder := toml.NewEncoder(buffer)
	tomlEncoder.SetIndentTables(false)
	encoder := &TOMLEncoder{
		writer:  w,
		encoder: tomlEncoder,
		buffer:  buffer,
	}
	for _, o := range options {
		o.ApplyEncoder(encoder)
	}
	return encoder
}

// Encode encodes the given value and writes the encodes bytes to the stream.
func (encoder *TOMLEncoder) Encode(v any) error {
	// No ordering is done here.
	adjusted := removeDencodingMap(v)
	if err := encoder.encoder.Encode(adjusted); err != nil {
		return err
	}
	data, err := io.ReadAll(encoder.buffer)
	if err != nil {
		return err
	}
	if _, err := encoder.writer.Write(data); err != nil {
		return err
	}
	newline := []byte("\n")
	if !bytes.HasSuffix(data, newline) {
		if _, err := encoder.writer.Write(newline); err != nil {
			return err
		}
	}
	return nil
}

// Close cleans up the encoder.
func (encoder *TOMLEncoder) Close() error {
	return nil
}

func removeDencodingMap(value any) any {
	switch v := value.(type) {
	case []any:
		return removeDencodingMapFromArray(v)
	case map[string]any:
		return removeDencodingMapFromMap(v)
	case *Map:
		return removeDencodingMap(v.data)
	default:
		return v
	}
}

func removeDencodingMapFromArray(value []any) []any {
	for k, v := range value {
		value[k] = removeDencodingMap(v)
	}
	return value
}

func removeDencodingMapFromMap(value map[string]any) map[string]any {
	for k, v := range value {
		value[k] = removeDencodingMap(v)
	}
	return value
}

// TOMLIndentSymbol sets the indentation when encoding TOML.
func TOMLIndentSymbol(symbol string) TOMLEncoderOption {
	return tomlEncodeSymbol{symbol: symbol}
}

type tomlEncodeSymbol struct {
	symbol string
}

func (option tomlEncodeSymbol) ApplyEncoder(encoder *TOMLEncoder) {
	encoder.encoder.SetIndentSymbol(option.symbol)
	encoder.encoder.SetIndentTables(option.symbol != "")
}