yq/pkg/yqlib/encoder_properties.go

149 lines
3.4 KiB
Go
Raw Normal View History

2021-07-25 01:43:51 +00:00
package yqlib
import (
"bufio"
"errors"
2021-07-25 01:43:51 +00:00
"fmt"
"io"
2021-07-27 11:51:27 +00:00
"strings"
2021-07-25 01:43:51 +00:00
"github.com/magiconair/properties"
)
type propertiesEncoder struct {
2024-02-24 04:14:21 +00:00
prefs PropertiesPreferences
2021-07-25 01:43:51 +00:00
}
2024-02-24 04:14:21 +00:00
func NewPropertiesEncoder(prefs PropertiesPreferences) Encoder {
return &propertiesEncoder{
2024-02-24 04:14:21 +00:00
prefs: prefs,
}
2021-07-25 01:43:51 +00:00
}
func (pe *propertiesEncoder) CanHandleAliases() bool {
return false
}
2024-01-11 02:17:34 +00:00
func (pe *propertiesEncoder) PrintDocumentSeparator(_ io.Writer) error {
return nil
}
func (pe *propertiesEncoder) PrintLeadingContent(writer io.Writer, content string) error {
reader := bufio.NewReader(strings.NewReader(content))
for {
readline, errReading := reader.ReadString('\n')
if errReading != nil && !errors.Is(errReading, io.EOF) {
return errReading
}
2023-09-18 23:52:36 +00:00
if strings.Contains(readline, "$yqDocSeparator$") {
if err := pe.PrintDocumentSeparator(writer); err != nil {
return err
}
} else {
if err := writeString(writer, readline); err != nil {
return err
}
}
if errors.Is(errReading, io.EOF) {
if readline != "" {
// the last comment we read didn't have a newline, put one in
if err := writeString(writer, "\n"); err != nil {
return err
}
}
break
}
}
return nil
}
func (pe *propertiesEncoder) Encode(writer io.Writer, node *CandidateNode) error {
2023-03-27 02:51:08 +00:00
if node.Kind == ScalarNode {
2023-03-27 02:51:08 +00:00
return writeString(writer, node.Value+"\n")
}
2021-07-25 01:43:51 +00:00
mapKeysToStrings(node)
p := properties.NewProperties()
p.WriteSeparator = pe.prefs.KeyValueSeparator
err := pe.doEncode(p, node, "", nil)
2021-07-25 01:43:51 +00:00
if err != nil {
return err
}
_, err = p.WriteComment(writer, "#", properties.UTF8)
2021-07-25 01:43:51 +00:00
return err
}
func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *CandidateNode, path string, keyNode *CandidateNode) error {
comments := ""
if keyNode != nil {
// include the key node comments if present
comments = headAndLineComment(keyNode)
}
comments = comments + headAndLineComment(node)
commentsWithSpaces := strings.ReplaceAll(comments, "\n", "\n ")
p.SetComments(path, strings.Split(commentsWithSpaces, "\n"))
2021-07-25 01:43:51 +00:00
switch node.Kind {
case ScalarNode:
var nodeValue string
2024-02-24 04:14:21 +00:00
if pe.prefs.UnwrapScalar || !strings.Contains(node.Value, " ") {
nodeValue = node.Value
} else {
nodeValue = fmt.Sprintf("%q", node.Value)
}
_, _, err := p.Set(path, nodeValue)
2021-07-25 08:08:33 +00:00
return err
case SequenceNode:
2021-07-25 01:43:51 +00:00
return pe.encodeArray(p, node.Content, path)
case MappingNode:
2021-07-25 01:43:51 +00:00
return pe.encodeMap(p, node.Content, path)
case AliasNode:
return pe.doEncode(p, node.Alias, path, nil)
2021-07-25 01:43:51 +00:00
default:
return fmt.Errorf("Unsupported node %v", node.Tag)
}
}
func (pe *propertiesEncoder) appendPath(path string, key interface{}) string {
if path == "" {
return fmt.Sprintf("%v", key)
}
switch key.(type) {
case int:
if pe.prefs.UseArrayBrackets {
return fmt.Sprintf("%v[%v]", path, key)
}
}
2021-07-25 01:43:51 +00:00
return fmt.Sprintf("%v.%v", path, key)
}
func (pe *propertiesEncoder) encodeArray(p *properties.Properties, kids []*CandidateNode, path string) error {
2021-07-25 01:43:51 +00:00
for index, child := range kids {
err := pe.doEncode(p, child, pe.appendPath(path, index), nil)
2021-07-25 01:43:51 +00:00
if err != nil {
return err
}
}
return nil
}
func (pe *propertiesEncoder) encodeMap(p *properties.Properties, kids []*CandidateNode, path string) error {
2021-07-25 01:43:51 +00:00
for index := 0; index < len(kids); index = index + 2 {
key := kids[index]
value := kids[index+1]
err := pe.doEncode(p, value, pe.appendPath(path, key.Value), key)
2021-07-25 01:43:51 +00:00
if err != nil {
return err
}
}
return nil
}