-
-
Notifications
You must be signed in to change notification settings - Fork 135
/
yaml.go
128 lines (109 loc) · 3.25 KB
/
yaml.go
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
128
package storage
import (
"bytes"
"fmt"
"github.com/tomwright/dasel/v2"
"github.com/tomwright/dasel/v2/dencoding"
"github.com/tomwright/dasel/v2/util"
"io"
)
func init() {
registerReadParser([]string{"yaml", "yml"}, []string{".yaml", ".yml"}, &YAMLParser{})
registerWriteParser([]string{"yaml", "yml"}, []string{".yaml", ".yml"}, &YAMLParser{})
}
// YAMLParser is a Parser implementation to handle yaml files.
type YAMLParser struct {
}
// FromBytes returns some data that is represented by the given bytes.
func (p *YAMLParser) FromBytes(byteData []byte, options ...ReadWriteOption) (dasel.Value, error) {
res := make([]interface{}, 0)
decoder := dencoding.NewYAMLDecoder(bytes.NewReader(byteData))
docLoop:
for {
var docData interface{}
if err := decoder.Decode(&docData); err != nil {
if err == io.EOF {
break docLoop
}
return dasel.Value{}, fmt.Errorf("could not unmarshal data: %w", err)
}
formattedDocData := cleanupYamlMapValue(docData)
res = append(res, formattedDocData)
}
switch len(res) {
case 0:
return dasel.Value{}, nil
case 1:
return dasel.ValueOf(res[0]).WithMetadata("isSingleDocument", true), nil
default:
return dasel.ValueOf(res).WithMetadata("isMultiDocument", true), nil
}
}
func cleanupYamlInterfaceArray(in []interface{}) []interface{} {
res := make([]interface{}, len(in))
for i, v := range in {
res[i] = cleanupYamlMapValue(v)
}
return res
}
func cleanupYamlInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
res := make(map[string]interface{})
for k, v := range in {
res[util.ToString(k)] = cleanupYamlMapValue(v)
}
return res
}
func cleanupYamlMapValue(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanupYamlInterfaceArray(v)
case map[interface{}]interface{}:
return cleanupYamlInterfaceMap(v)
case string:
return v
default:
return v
}
}
// ToBytes returns a slice of bytes that represents the given value.
func (p *YAMLParser) ToBytes(value dasel.Value, options ...ReadWriteOption) ([]byte, error) {
buffer := new(bytes.Buffer)
colourise := false
encoderOptions := make([]dencoding.YAMLEncoderOption, 0)
for _, o := range options {
switch o.Key {
case OptionColourise:
if value, ok := o.Value.(bool); ok {
colourise = value
}
case OptionIndent:
if value, ok := o.Value.(string); ok {
encoderOptions = append(encoderOptions, dencoding.YAMLEncodeIndent(len(value)))
}
}
}
encoder := dencoding.NewYAMLEncoder(buffer, encoderOptions...)
defer encoder.Close()
switch {
case value.Metadata("isSingleDocument") == true:
if err := encoder.Encode(value.Interface()); err != nil {
return nil, fmt.Errorf("could not encode single document: %w", err)
}
case value.Metadata("isMultiDocument") == true:
for i := 0; i < value.Len(); i++ {
if err := encoder.Encode(value.Index(i).Interface()); err != nil {
return nil, fmt.Errorf("could not encode multi document [%d]: %w", i, err)
}
}
default:
if err := encoder.Encode(value.Interface()); err != nil {
return nil, fmt.Errorf("could not encode default document type: %w", err)
}
}
if colourise {
if err := ColouriseBuffer(buffer, "yaml"); err != nil {
return nil, fmt.Errorf("could not colourise output: %w", err)
}
}
return buffer.Bytes(), nil
}