Repository: goccy/go-yaml
Pull request #635 (2025-02-03 03:49:15)

Fix comment map
fix https://github.com/goccy/go-yaml/issues/634

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/goccy/go-yaml/pull/635?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 77.39%. Comparing base [(`c8cc5c5`)](https://app.codecov.io/gh/goccy/go-yaml/commit/c8cc5c583fe5c313b35b75f5abe8c365922b88f7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) to head [(`68b43fa`)](https://app.codecov.io/gh/goccy/go-yaml/commit/68b43faa9d6730a3106a051c1618b36037b87e3a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima).

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #635      +/-   ##
==========================================
+ Coverage   77.37%   77.39%   +0.01%     
==========================================
  Files          22       22              
  Lines        7890     7896       +6     
==========================================
+ Hits         6105     6111       +6     
  Misses       1368     1368              
  Partials      417      417              
```

</details>

Patch:
diff --git a/decode.go b/decode.go
index 779ecb5..0191a39 100644
--- a/decode.go
+++ b/decode.go
@@ -7,6 +7,7 @@ import (
 	"encoding/base64"
 	"fmt"
 	"io"
+	"maps"
 	"math"
 	"os"
 	"path/filepath"
@@ -30,6 +31,7 @@ type Decoder struct {
 	aliasValueMap        map[*ast.AliasNode]any
 	anchorValueMap       map[string]reflect.Value
 	customUnmarshalerMap map[reflect.Type]func(interface{}, []byte) error
+	commentMaps          []CommentMap
 	toCommentMap         CommentMap
 	opts                 []DecodeOption
 	referenceFiles       []string
@@ -1957,6 +1959,12 @@ func (d *Decoder) parse(bytes []byte) (*ast.File, error) {
 		if v != nil {
 			normalizedFile.Docs = append(normalizedFile.Docs, doc)
 		}
+		cm := CommentMap{}
+		maps.Copy(cm, d.toCommentMap)
+		d.commentMaps = append(d.commentMaps, cm)
+		for k := range d.toCommentMap {
+			delete(d.toCommentMap, k)
+		}
 	}
 	return normalizedFile, nil
 }
@@ -1980,9 +1988,6 @@ func (d *Decoder) decodeInit() error {
 		return err
 	}
 	d.parsedFile = file
-	for k := range d.toCommentMap {
-		delete(d.toCommentMap, k)
-	}
 	return nil
 }
 
@@ -1995,6 +2000,9 @@ func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
 	if body == nil {
 		return nil
 	}
+	if len(d.commentMaps) > d.streamIndex {
+		maps.Copy(d.toCommentMap, d.commentMaps[d.streamIndex])
+	}
 	if err := d.decodeValue(ctx, v.Elem(), body); err != nil {
 		return err
 	}


Test patch:
diff --git a/yaml_test.go b/yaml_test.go
new file mode 100644
index 0000000..560a93c
--- /dev/null
+++ b/yaml_test.go
@@ -0,0 +1,74 @@
+package yaml_test
+
+import (
+	"io"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/goccy/go-yaml"
+)
+
+func TestRoundTripWithComment(t *testing.T) {
+	yml := `
+# head comment
+key: value # line comment
+`
+	var v struct {
+		Key string
+	}
+	comments := yaml.CommentMap{}
+
+	if err := yaml.UnmarshalWithOptions([]byte(yml), &v, yaml.Strict(), yaml.CommentToMap(comments)); err != nil {
+		t.Fatal(err)
+	}
+	out, err := yaml.MarshalWithOptions(v, yaml.WithComment(comments))
+	if err != nil {
+		t.Fatal(err)
+	}
+	got := "\n" + string(out)
+	if yml != got {
+		t.Fatalf("failed to get round tripped yaml: %s", got)
+	}
+}
+
+func TestStreamDecodingWithComment(t *testing.T) {
+	yml := `
+a:
+  b:
+    c: # comment
+---
+foo: bar # comment
+---
+- a
+- b
+- c # comment
+`
+	cm := yaml.CommentMap{}
+	dec := yaml.NewDecoder(strings.NewReader(yml), yaml.CommentToMap(cm))
+	var commentPathsWithDocIndex [][]string
+	for {
+		var v any
+		if err := dec.Decode(&v); err != nil {
+			if err == io.EOF {
+				break
+			}
+			t.Fatal(err)
+		}
+		paths := make([]string, 0, len(cm))
+		for k := range cm {
+			paths = append(paths, k)
+		}
+		commentPathsWithDocIndex = append(commentPathsWithDocIndex, paths)
+		for k := range cm {
+			delete(cm, k)
+		}
+	}
+	if !reflect.DeepEqual(commentPathsWithDocIndex, [][]string{
+		{"$.a.b.c"},
+		{"$.foo"},
+		{"$[2]"},
+	}) {
+		t.Fatalf("failed to get comment: %v", commentPathsWithDocIndex)
+	}
+}