diff --git a/examples/data1.yaml b/examples/data1.yaml index d75578de..a15395fa 100644 --- a/examples/data1.yaml +++ b/examples/data1.yaml @@ -1 +1,2 @@ -a: the cute cat wrote a long sentence that wasn't wrapped at all. the cute cat wrote a long sentence that wasn't wrapped at all. \ No newline at end of file +a: #things + meow \ No newline at end of file diff --git a/pkg/yqlib/candidate_node_goccy_yaml.go b/pkg/yqlib/candidate_node_goccy_yaml.go index c3b45536..ea14494f 100644 --- a/pkg/yqlib/candidate_node_goccy_yaml.go +++ b/pkg/yqlib/candidate_node_goccy_yaml.go @@ -2,22 +2,53 @@ package yqlib import ( "fmt" + "strings" + yaml "github.com/goccy/go-yaml" "github.com/goccy/go-yaml/ast" goccyToken "github.com/goccy/go-yaml/token" ) -func (o *CandidateNode) goccyDecodeIntoChild(childNode ast.Node, anchorMap map[string]*CandidateNode) (*CandidateNode, error) { +func (o *CandidateNode) goccyDecodeIntoChild(childNode ast.Node, cm yaml.CommentMap) (*CandidateNode, error) { newChild := o.CreateChild() - err := newChild.UnmarshalGoccyYAML(childNode, anchorMap) + err := newChild.UnmarshalGoccyYAML(childNode, cm) return newChild, err } -func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, anchorMap map[string]*CandidateNode) error { +func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, cm yaml.CommentMap) error { log.Debugf("UnmarshalYAML %v", node) log.Debugf("UnmarshalYAML %v", node.Type().String()) - log.Debugf("UnmarshalYAML Value: %v", node.String()) + log.Debugf("UnmarshalYAML Node Value: %v", node.String()) + log.Debugf("UnmarshalYAML Node GetComment: %v", node.GetComment()) + + if node.GetComment() != nil { + commentMapComments := cm[node.GetPath()] + for _, comment := range node.GetComment().Comments { + // need to use the comment map to find the position :/ + log.Debugf("%v has a comment of [%v]", node.GetPath(), comment.Token.Value) + for _, commentMapComment := range commentMapComments { + commentMapValue := strings.Join(commentMapComment.Texts, "\n") + if commentMapValue == comment.Token.Value { + log.Debug("found a matching entry in comment map") + // we found the comment in the comment map, + // now we can process the position + switch commentMapComment.Position { + case yaml.CommentHeadPosition: + o.HeadComment = comment.String() + log.Debug("its a head comment %v", comment.String()) + case yaml.CommentLinePosition: + o.LineComment = comment.String() + log.Debug("its a line comment %v", comment.String()) + case yaml.CommentFootPosition: + o.FootComment = comment.String() + log.Debug("its a foot comment %v", comment.String()) + } + } + } + + } + } o.Value = node.String() switch node.Type() { @@ -43,40 +74,46 @@ func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, anchorMap map[string]* o.Tag = "!!str" o.Style = LiteralStyle astLiteral := node.(*ast.LiteralNode) + log.Debugf("astLiteral.Start.Type %v", astLiteral.Start.Type) if astLiteral.Start.Type == goccyToken.FoldedType { + log.Debugf("folded Type %v", astLiteral.Start.Type) o.Style = FoldedStyle } - log.Debug("startvalue: %v ", node.(*ast.LiteralNode).Start.Value) - log.Debug("startvalue: %v ", node.(*ast.LiteralNode).Start.Type) + log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Value) + log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Type) + // TODO: here I could put the original value with line breaks + // to solve the multiline > problem o.Value = astLiteral.Value.Value case ast.TagType: - o.UnmarshalGoccyYAML(node.(*ast.TagNode).Value, anchorMap) + o.UnmarshalGoccyYAML(node.(*ast.TagNode).Value, cm) o.Tag = node.(*ast.TagNode).Start.Value - case ast.MappingValueType, ast.MappingType: + case ast.MappingType: log.Debugf("UnmarshalYAML - a mapping node") o.Kind = MappingNode o.Tag = "!!map" - if node.Type() == ast.MappingType { + mappingNode := node.(*ast.MappingNode) + if mappingNode.IsFlowStyle { o.Style = FlowStyle } - - astMapIter := node.(ast.MapNode).MapRange() - for astMapIter.Next() { - log.Debug("UnmarshalYAML map entry %v", astMapIter.Key().String()) - keyNode, err := o.goccyDecodeIntoChild(astMapIter.Key(), anchorMap) + for _, mappingValueNode := range mappingNode.Values { + err := o.goccyProcessMappingValueNode(mappingValueNode, cm) if err != nil { - return err + return ast.ErrInvalidAnchorName } - - keyNode.IsMapKey = true - log.Debug("UnmarshalYAML map value %v", astMapIter.Value().String()) - valueNode, err := o.goccyDecodeIntoChild(astMapIter.Value(), anchorMap) - if err != nil { - return err - } - - o.Content = append(o.Content, keyNode, valueNode) + } + if mappingNode.FootComment != nil { + log.Debugf("mapping node has a foot comment of: %v", mappingNode.FootComment) + o.FootComment = mappingNode.FootComment.String() + } + case ast.MappingValueType: + log.Debugf("UnmarshalYAML - a mapping node") + o.Kind = MappingNode + o.Tag = "!!map" + mappingValueNode := node.(*ast.MappingValueNode) + err := o.goccyProcessMappingValueNode(mappingValueNode, cm) + if err != nil { + return ast.ErrInvalidAnchorName } case ast.SequenceType: log.Debugf("UnmarshalYAML - a sequence node") @@ -95,7 +132,7 @@ func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, anchorMap map[string]* keyNode.Kind = ScalarNode keyNode.Value = fmt.Sprintf("%v", i) - valueNode, err := o.goccyDecodeIntoChild(astSeq[i], anchorMap) + valueNode, err := o.goccyDecodeIntoChild(astSeq[i], cm) if err != nil { return err } @@ -110,3 +147,26 @@ func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, anchorMap map[string]* log.Debugf("KIND: %v", o.Kind) return nil } + +func (o *CandidateNode) goccyProcessMappingValueNode(mappingEntry *ast.MappingValueNode, cm yaml.CommentMap) error { + log.Debug("UnmarshalYAML MAP KEY entry %v", mappingEntry.Key) + keyNode, err := o.goccyDecodeIntoChild(mappingEntry.Key, cm) + if err != nil { + return err + } + keyNode.IsMapKey = true + + log.Debug("UnmarshalYAML MAP VALUE entry %v", mappingEntry.Value) + valueNode, err := o.goccyDecodeIntoChild(mappingEntry.Value, cm) + if err != nil { + return err + } + + if mappingEntry.FootComment != nil { + valueNode.FootComment = mappingEntry.FootComment.String() + } + + o.Content = append(o.Content, keyNode, valueNode) + + return nil +} diff --git a/pkg/yqlib/decoder_goccy_yaml.go b/pkg/yqlib/decoder_goccy_yaml.go index 3f6b7a58..5b7aec1b 100644 --- a/pkg/yqlib/decoder_goccy_yaml.go +++ b/pkg/yqlib/decoder_goccy_yaml.go @@ -11,6 +11,7 @@ import ( type goccyYamlDecoder struct { decoder yaml.Decoder + cm yaml.CommentMap } func NewGoccyYAMLDecoder() Decoder { @@ -18,7 +19,8 @@ func NewGoccyYAMLDecoder() Decoder { } func (dec *goccyYamlDecoder) Init(reader io.Reader) error { - dec.decoder = *yaml.NewDecoder(reader) + dec.cm = yaml.CommentMap{} + dec.decoder = *yaml.NewDecoder(reader, yaml.CommentToMap(dec.cm)) return nil } @@ -28,15 +30,11 @@ func (dec *goccyYamlDecoder) Decode() (*CandidateNode, error) { err := dec.decoder.Decode(&ast) if err != nil { - log.Debug("badasda: %v", err) - return nil, err } - log.Debug("ASTasdasdadasd: %v", ast.Type().String()) - candidateNode := &CandidateNode{} - candidateNode.UnmarshalGoccyYAML(ast, nil) + candidateNode.UnmarshalGoccyYAML(ast, dec.cm) return candidateNode, nil } diff --git a/pkg/yqlib/goccy_yaml_test.go b/pkg/yqlib/goccy_yaml_test.go index 327032cb..1410c435 100644 --- a/pkg/yqlib/goccy_yaml_test.go +++ b/pkg/yqlib/goccy_yaml_test.go @@ -32,6 +32,12 @@ var goccyYamlFormatScenarios = []formatScenario{ // expected: "{mike: 3}\n", // }, // { + // description: "basic - map multiple entries", + // skipDoc: true, + // input: "mike: 3\nfred: 12\n", + // expected: "mike: 3\nfred: 12\n", + // }, + // { // description: "basic - 3.1", // skipDoc: true, // input: "{\nmike: 3\n}", @@ -91,11 +97,29 @@ var goccyYamlFormatScenarios = []formatScenario{ // input: "a: |-\n meow\n", // expected: "a: |-\n meow\n", // }, + // { + // description: "basic - line comment", + // skipDoc: true, + // input: "a: meow # line comment\n", + // expected: "a: meow # line comment\n", + // }, + // { + // description: "basic - line comment", + // skipDoc: true, + // input: "# head comment\na: #line comment\n meow\n", + // expected: "# head comment\na: meow #line comment\n", // go-yaml does this + // }, { - description: "basic - string block", + description: "basic - foot comment", skipDoc: true, - input: "a: >\n meow\n", - expected: "a: >\n meow\n", + input: "a: meow\n# foot comment\n", + expected: "a: meow\n# foot comment\n", + }, + { + description: "basic - foot comment", + skipDoc: true, + input: "a: meow\nb: woof\n# foot comment\n", + expected: "a: meow\nb: woof\n# foot comment\n", }, }