2021-09-27 00:38:15 +00:00
|
|
|
package yml
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
2021-12-07 00:13:02 +00:00
|
|
|
"strconv"
|
2021-09-27 00:38:15 +00:00
|
|
|
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
// toJSON convert gopkg.in/yaml.v3 nodes to object that can be serialized as json
|
2021-09-27 00:38:15 +00:00
|
|
|
// fmt.Sprint() with default formatting is used to convert the key to a string key.
|
2021-12-07 00:13:02 +00:00
|
|
|
func toJSON(node *yaml.Node) (interface{}, error) {
|
|
|
|
switch node.Kind {
|
|
|
|
case yaml.DocumentNode:
|
|
|
|
return toJSON(node.Content[0])
|
|
|
|
|
|
|
|
case yaml.SequenceNode:
|
|
|
|
val := make([]interface{}, len(node.Content))
|
|
|
|
var err error
|
|
|
|
for i := range node.Content {
|
|
|
|
if val[i], err = toJSON(node.Content[i]); err != nil {
|
|
|
|
return nil, err
|
2021-09-27 00:38:15 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-07 00:13:02 +00:00
|
|
|
return val, nil
|
2021-09-27 00:38:15 +00:00
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
case yaml.MappingNode:
|
|
|
|
if (len(node.Content) % 2) != 0 {
|
|
|
|
return nil, fmt.Errorf("broken mapping node")
|
2021-09-27 00:38:15 +00:00
|
|
|
}
|
2021-12-07 00:13:02 +00:00
|
|
|
val := make(map[string]interface{}, len(node.Content)%2)
|
|
|
|
for i := len(node.Content); i > 1; i = i - 2 {
|
|
|
|
k, err := toJSON(node.Content[i-2])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if val[fmt.Sprint(k)], err = toJSON(node.Content[i-1]); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val, nil
|
2021-09-27 00:38:15 +00:00
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
case yaml.ScalarNode:
|
|
|
|
switch node.Tag {
|
|
|
|
case nullTag:
|
|
|
|
return nil, nil
|
|
|
|
case boolTag:
|
|
|
|
return strconv.ParseBool(node.Value)
|
|
|
|
case intTag:
|
|
|
|
return strconv.ParseInt(node.Value, 10, 64)
|
|
|
|
case floatTag:
|
|
|
|
return strconv.ParseFloat(node.Value, 64)
|
2021-09-27 00:38:15 +00:00
|
|
|
}
|
2021-12-07 00:13:02 +00:00
|
|
|
return node.Value, nil
|
2021-09-27 00:38:15 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
return nil, fmt.Errorf("do not support yaml node kind '%v'", node.Kind)
|
2021-09-27 00:38:15 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
func ToJSON(data []byte) ([]byte, error) {
|
|
|
|
m := &yaml.Node{}
|
|
|
|
if err := yaml.Unmarshal(data, m); err != nil {
|
2021-09-27 00:38:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
d, err := toJSON(m)
|
2021-12-06 18:17:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-12-07 00:13:02 +00:00
|
|
|
return json.Marshal(d)
|
2021-12-06 18:17:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func LoadYmlFileAsJSON(path string) (j []byte, err error) {
|
|
|
|
data, err := os.ReadFile(path)
|
2021-09-27 00:38:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-07 00:13:02 +00:00
|
|
|
j, err = ToJSON(data)
|
2021-09-27 00:38:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return j, nil
|
|
|
|
}
|
2021-12-07 00:13:02 +00:00
|
|
|
|
|
|
|
// Source: https://github.com/go-yaml/yaml/blob/3e3283e801afc229479d5fc68aa41df1137b8394/resolve.go#L70-L81
|
|
|
|
const (
|
|
|
|
nullTag = "!!null"
|
|
|
|
boolTag = "!!bool"
|
|
|
|
intTag = "!!int"
|
|
|
|
floatTag = "!!float"
|
|
|
|
// strTag = "!!str" // we dont have to parse it
|
|
|
|
// timestampTag = "!!timestamp" // TODO: do we have to parse this?
|
|
|
|
// seqTag = "!!seq" // TODO: do we have to parse this?
|
|
|
|
// mapTag = "!!map" // TODO: do we have to parse this?
|
|
|
|
// binaryTag = "!!binary" // TODO: do we have to parse this?
|
|
|
|
// mergeTag = "!!merge" // TODO: do we have to parse this?
|
|
|
|
)
|