Skip to content

Commit

Permalink
Merge pull request #253 from goccy/feature/support-decode-comment
Browse files Browse the repository at this point in the history
Support CommentToMap option
  • Loading branch information
goccy authored Sep 7, 2021
2 parents e9d5e8f + b034e1c commit 82ab4c7
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 1 deletion.
31 changes: 30 additions & 1 deletion decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Decoder struct {
referenceReaders []io.Reader
anchorNodeMap map[string]ast.Node
anchorValueMap map[string]reflect.Value
toCommentMap CommentMap
opts []DecodeOption
referenceFiles []string
referenceDirs []string
Expand Down Expand Up @@ -115,6 +116,7 @@ func (d *Decoder) mapKeyNodeToString(node ast.Node) string {
}

func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) {
d.setPathToCommentMap(node)
switch n := node.(type) {
case *ast.MappingValueNode:
if n.Key.Type() == ast.MergeKeyType {
Expand Down Expand Up @@ -149,7 +151,30 @@ func (d *Decoder) setToOrderedMapValue(node ast.Node, m *MapSlice) {
}
}

func (d *Decoder) setPathToCommentMap(node ast.Node) {
if d.toCommentMap == nil {
return
}
commentGroup := node.GetComment()
if commentGroup == nil {
return
}
texts := []string{}
for _, comment := range commentGroup.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) == 0 {
return
}
if len(texts) == 1 {
d.toCommentMap[node.GetPath()] = LineComment(texts[0])
} else {
d.toCommentMap[node.GetPath()] = HeadComment(texts...)
}
}

func (d *Decoder) nodeToValue(node ast.Node) interface{} {
d.setPathToCommentMap(node)
switch n := node.(type) {
case *ast.NullNode:
return nil
Expand Down Expand Up @@ -1434,7 +1459,11 @@ func (d *Decoder) resolveReference() error {
}

func (d *Decoder) parse(bytes []byte) (*ast.File, error) {
f, err := parser.ParseBytes(bytes, 0)
var parseMode parser.Mode
if d.toCommentMap != nil {
parseMode = parser.ParseComments
}
f, err := parser.ParseBytes(bytes, parseMode)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse yaml")
}
Expand Down
1 change: 1 addition & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var (
ErrInvalidPathString = xerrors.New("invalid path string")
ErrNotFoundNode = xerrors.New("node not found")
ErrUnknownCommentPositionType = xerrors.New("unknown comment position type")
ErrInvalidCommentMapValue = xerrors.New("invalid comment map value. it must be not nil value")
)

func ErrUnsupportedHeadPositionType(node ast.Node) error {
Expand Down
11 changes: 11 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,14 @@ func WithComment(cm CommentMap) EncodeOption {
return nil
}
}

// CommentToMap apply the position and content of comments in a YAML document to a CommentMap.
func CommentToMap(cm CommentMap) DecodeOption {
return func(d *Decoder) error {
if cm == nil {
return ErrInvalidCommentMapValue
}
d.toCommentMap = cm
return nil
}
}
116 changes: 116 additions & 0 deletions yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package yaml_test

import (
"bytes"
"reflect"
"testing"

"github.com/goccy/go-yaml"
Expand Down Expand Up @@ -466,3 +467,118 @@ baz:
}
})
}

func Test_CommentToMapOption(t *testing.T) {
t.Run("line comment", func(t *testing.T) {
yml := `
foo: aaa #foo comment
bar: #bar comment
bbb: ccc #bbb comment
baz:
x: 10 #x comment
`
var (
v interface{}
cm = yaml.CommentMap{}
)
if err := yaml.UnmarshalWithOptions([]byte(yml), &v, yaml.CommentToMap(cm)); err != nil {
t.Fatal(err)
}
expected := []struct {
path string
comment *yaml.Comment
}{
{
path: "$.foo",
comment: yaml.LineComment("foo comment"),
},
{
path: "$.bar",
comment: yaml.LineComment("bar comment"),
},
{
path: "$.bar.bbb",
comment: yaml.LineComment("bbb comment"),
},
{
path: "$.baz.x",
comment: yaml.LineComment("x comment"),
},
}
for _, exp := range expected {
comment := cm[exp.path]
if comment == nil {
t.Fatalf("failed to get path %s", exp.path)
}
if !reflect.DeepEqual(exp.comment, comment) {
t.Fatalf("failed to get comment. expected:[%+v] but got:[%+v]", exp.comment, comment)
}
}
})
t.Run("head comment", func(t *testing.T) {
yml := `
#foo comment
#foo comment2
foo: aaa
#bar comment
#bar comment2
bar:
#bbb comment
#bbb comment2
bbb: ccc
baz:
#x comment
#x comment2
x: 10
`
var (
v interface{}
cm = yaml.CommentMap{}
)
if err := yaml.UnmarshalWithOptions([]byte(yml), &v, yaml.CommentToMap(cm)); err != nil {
t.Fatal(err)
}
expected := []struct {
path string
comment *yaml.Comment
}{
{
path: "$.foo",
comment: yaml.HeadComment(
"foo comment",
"foo comment2",
),
},
{
path: "$.bar",
comment: yaml.HeadComment(
"bar comment",
"bar comment2",
),
},
{
path: "$.bar.bbb",
comment: yaml.HeadComment(
"bbb comment",
"bbb comment2",
),
},
{
path: "$.baz.x",
comment: yaml.HeadComment(
"x comment",
"x comment2",
),
},
}
for _, exp := range expected {
comment := cm[exp.path]
if comment == nil {
t.Fatalf("failed to get path %s", exp.path)
}
if !reflect.DeepEqual(exp.comment, comment) {
t.Fatalf("failed to get comment. expected:[%+v] but got:[%+v]", exp.comment, comment)
}
}
})
}

0 comments on commit 82ab4c7

Please sign in to comment.