Skip to content

Commit

Permalink
Fix comment option (#349)
Browse files Browse the repository at this point in the history
  • Loading branch information
goccy authored Mar 1, 2023
1 parent 6cdefc4 commit 1564006
Show file tree
Hide file tree
Showing 10 changed files with 949 additions and 123 deletions.
40 changes: 26 additions & 14 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ func (n *NullNode) GetValue() interface{} {
// String returns `null` text
func (n *NullNode) String() string {
if n.Comment != nil {
return fmt.Sprintf("null %s", n.Comment.String())
return addCommentString("null", n.Comment)
}
return n.stringWithoutComment()
}
Expand Down Expand Up @@ -1154,6 +1154,7 @@ type MappingNode struct {
End *token.Token
IsFlowStyle bool
Values []*MappingValueNode
FootComment *CommentGroupNode
}

func (n *MappingNode) startPos() *token.Position {
Expand Down Expand Up @@ -1319,9 +1320,10 @@ func (n *MappingKeyNode) MarshalYAML() ([]byte, error) {
// MappingValueNode type of mapping value
type MappingValueNode struct {
*BaseNode
Start *token.Token
Key MapKeyNode
Value Node
Start *token.Token
Key MapKeyNode
Value Node
FootComment *CommentGroupNode
}

// Replace replace value node.
Expand Down Expand Up @@ -1370,14 +1372,20 @@ func (n *MappingValueNode) SetIsFlowStyle(isFlow bool) {

// String mapping value to text
func (n *MappingValueNode) String() string {
var text string
if n.Comment != nil {
return fmt.Sprintf(
text = fmt.Sprintf(
"%s\n%s",
n.Comment.StringWithSpace(n.Key.GetToken().Position.Column-1),
n.toString(),
)
} else {
text = n.toString()
}
return n.toString()
if n.FootComment != nil {
text += fmt.Sprintf("\n%s", n.FootComment.StringWithSpace(n.Key.GetToken().Position.Column-1))
}
return text
}

func (n *MappingValueNode) toString() string {
Expand Down Expand Up @@ -1472,11 +1480,12 @@ func (m *ArrayNodeIter) Len() int {
// SequenceNode type of sequence node
type SequenceNode struct {
*BaseNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []Node
ValueComments []*CommentGroupNode
Start *token.Token
End *token.Token
IsFlowStyle bool
Values []Node
ValueHeadComments []*CommentGroupNode
FootComment *CommentGroupNode
}

// Replace replace value node.
Expand Down Expand Up @@ -1576,11 +1585,14 @@ func (n *SequenceNode) blockStyleString() string {
newValues = append(newValues, fmt.Sprintf("%s %s", space, trimmed))
}
newValue := strings.Join(newValues, "\n")
if len(n.ValueComments) == len(n.Values) && n.ValueComments[idx] != nil {
values = append(values, n.ValueComments[idx].StringWithSpace(n.Start.Position.Column-1))
if len(n.ValueHeadComments) == len(n.Values) && n.ValueHeadComments[idx] != nil {
values = append(values, n.ValueHeadComments[idx].StringWithSpace(n.Start.Position.Column-1))
}
values = append(values, fmt.Sprintf("%s- %s", space, newValue))
}
if n.FootComment != nil {
values = append(values, n.FootComment.StringWithSpace(n.Start.Position.Column-1))
}
return strings.Join(values, "\n")
}

Expand Down Expand Up @@ -1866,8 +1878,8 @@ func (n *CommentGroupNode) String() string {
}

func (n *CommentGroupNode) StringWithSpace(col int) string {
space := strings.Repeat(" ", col)
values := []string{}
space := strings.Repeat(" ", col)
for _, comment := range n.Comments {
values = append(values, space+comment.String())
}
Expand Down
91 changes: 88 additions & 3 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os"
"path/filepath"
"reflect"
"sort"
"strconv"
"time"

Expand Down Expand Up @@ -155,22 +156,106 @@ func (d *Decoder) setPathToCommentMap(node ast.Node) {
if d.toCommentMap == nil {
return
}
d.addHeadOrLineCommentToMap(node)
d.addFootCommentToMap(node)
}

func (d *Decoder) addHeadOrLineCommentToMap(node ast.Node) {
sequence, ok := node.(*ast.SequenceNode)
if ok {
d.addSequenceNodeCommentToMap(sequence)
return
}
commentGroup := node.GetComment()
if commentGroup == nil {
return
}
texts := []string{}
targetLine := node.GetToken().Position.Line
minCommentLine := math.MaxInt64
for _, comment := range commentGroup.Comments {
if minCommentLine > comment.Token.Position.Line {
minCommentLine = comment.Token.Position.Line
}
texts = append(texts, comment.Token.Value)
}
if len(texts) == 0 {
return
}
if len(texts) == 1 {
d.toCommentMap[node.GetPath()] = LineComment(texts[0])
commentPath := node.GetPath()
if minCommentLine < targetLine {
d.addCommentToMap(commentPath, HeadComment(texts...))
} else {
d.toCommentMap[node.GetPath()] = HeadComment(texts...)
d.addCommentToMap(commentPath, LineComment(texts[0]))
}
}

func (d *Decoder) addSequenceNodeCommentToMap(node *ast.SequenceNode) {
if len(node.ValueHeadComments) != 0 {
for idx, headComment := range node.ValueHeadComments {
if headComment == nil {
continue
}
texts := make([]string, 0, len(headComment.Comments))
for _, comment := range headComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(node.Values[idx].GetPath(), HeadComment(texts...))
}
}
}
firstElemHeadComment := node.GetComment()
if firstElemHeadComment != nil {
texts := make([]string, 0, len(firstElemHeadComment.Comments))
for _, comment := range firstElemHeadComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(node.Values[0].GetPath(), HeadComment(texts...))
}
}
}

func (d *Decoder) addFootCommentToMap(node ast.Node) {
var (
footComment *ast.CommentGroupNode
footCommentPath string = node.GetPath()
)
switch n := node.(type) {
case *ast.SequenceNode:
if len(n.Values) != 0 {
footCommentPath = n.Values[len(n.Values)-1].GetPath()
}
footComment = n.FootComment
case *ast.MappingNode:
footComment = n.FootComment
case *ast.MappingValueNode:
footComment = n.FootComment
}
if footComment == nil {
return
}
var texts []string
for _, comment := range footComment.Comments {
texts = append(texts, comment.Token.Value)
}
if len(texts) != 0 {
d.addCommentToMap(footCommentPath, FootComment(texts...))
}
}

func (d *Decoder) addCommentToMap(path string, comment *Comment) {
for _, c := range d.toCommentMap[path] {
if c.Position == comment.Position {
// already added same comment
return
}
}
d.toCommentMap[path] = append(d.toCommentMap[path], comment)
sort.Slice(d.toCommentMap[path], func(i, j int) bool {
return d.toCommentMap[path][i].Position < d.toCommentMap[path][j].Position
})
}

func (d *Decoder) nodeToValue(node ast.Node) interface{} {
Expand Down
132 changes: 107 additions & 25 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Encoder struct {
anchorCallback func(*ast.AnchorNode, interface{}) error
anchorPtrToNameMap map[uintptr]string
useLiteralStyleIfMultiline bool
commentMap map[*Path]*Comment
commentMap map[*Path][]*Comment
written bool

line int
Expand Down Expand Up @@ -121,41 +121,123 @@ func (e *Encoder) setCommentByCommentMap(node ast.Node) error {
if e.commentMap == nil {
return nil
}
for path, comment := range e.commentMap {
for path, comments := range e.commentMap {
n, err := path.FilterNode(node)
if err != nil {
return errors.Wrapf(err, "failed to filter node")
}
comments := []*token.Token{}
for _, text := range comment.Texts {
comments = append(comments, token.New(text, text, nil))
if n == nil {
continue
}
commentGroup := ast.CommentGroup(comments)
switch comment.Position {
case CommentLinePosition:
if err := n.SetComment(commentGroup); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
case CommentHeadPosition:
parent := ast.Parent(node, n)
if parent == nil {
return ErrUnsupportedHeadPositionType(node)
for _, comment := range comments {
commentTokens := []*token.Token{}
for _, text := range comment.Texts {
commentTokens = append(commentTokens, token.New(text, text, nil))
}
switch node := parent.(type) {
case *ast.MappingValueNode:
if err := node.SetComment(commentGroup); err != nil {
return errors.Wrapf(err, "failed to set comment")
commentGroup := ast.CommentGroup(commentTokens)
switch comment.Position {
case CommentHeadPosition:
if err := e.setHeadComment(node, n, commentGroup); err != nil {
return errors.Wrapf(err, "failed to set head comment")
}
case CommentLinePosition:
if err := e.setLineComment(node, n, commentGroup); err != nil {
return errors.Wrapf(err, "failed to set line comment")
}
case *ast.MappingNode:
if err := node.SetComment(commentGroup); err != nil {
return errors.Wrapf(err, "failed to set comment")
case CommentFootPosition:
if err := e.setFootComment(node, n, commentGroup); err != nil {
return errors.Wrapf(err, "failed to set foot comment")
}
default:
return ErrUnsupportedHeadPositionType(node)
return ErrUnknownCommentPositionType
}
}
}
return nil
}

func (e *Encoder) setHeadComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedHeadPositionType(node)
}
switch p := parent.(type) {
case *ast.MappingValueNode:
if err := p.SetComment(comment); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
case *ast.MappingNode:
if err := p.SetComment(comment); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
case *ast.SequenceNode:
if len(p.ValueHeadComments) == 0 {
p.ValueHeadComments = make([]*ast.CommentGroupNode, len(p.Values))
}
var foundIdx int
for idx, v := range p.Values {
if v == filtered {
foundIdx = idx
break
}
default:
return ErrUnknownCommentPositionType
}
p.ValueHeadComments[foundIdx] = comment
default:
return ErrUnsupportedHeadPositionType(node)
}
return nil
}

func (e *Encoder) setLineComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
switch filtered.(type) {
case *ast.MappingValueNode, *ast.SequenceNode:
// Line comment cannot be set for mapping value node.
// It should probably be set for the parent map node
if err := e.setLineCommentToParentMapNode(node, filtered, comment); err != nil {
return errors.Wrapf(err, "failed to set line comment to parent node")
}
default:
if err := filtered.SetComment(comment); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
}
return nil
}

func (e *Encoder) setLineCommentToParentMapNode(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedLinePositionType(node)
}
switch p := parent.(type) {
case *ast.MappingValueNode:
if err := p.Key.SetComment(comment); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
case *ast.MappingNode:
if err := p.SetComment(comment); err != nil {
return errors.Wrapf(err, "failed to set comment")
}
default:
return ErrUnsupportedLinePositionType(parent)
}
return nil
}

func (e *Encoder) setFootComment(node ast.Node, filtered ast.Node, comment *ast.CommentGroupNode) error {
parent := ast.Parent(node, filtered)
if parent == nil {
return ErrUnsupportedFootPositionType(node)
}
switch n := parent.(type) {
case *ast.MappingValueNode:
n.FootComment = comment
case *ast.MappingNode:
n.FootComment = comment
case *ast.SequenceNode:
n.FootComment = comment
default:
return ErrUnsupportedFootPositionType(n)
}
return nil
}
Expand Down
8 changes: 8 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ func ErrUnsupportedHeadPositionType(node ast.Node) error {
return xerrors.Errorf("unsupported comment head position for %s", node.Type())
}

func ErrUnsupportedLinePositionType(node ast.Node) error {
return xerrors.Errorf("unsupported comment line position for %s", node.Type())
}

func ErrUnsupportedFootPositionType(node ast.Node) error {
return xerrors.Errorf("unsupported comment foot position for %s", node.Type())
}

// IsInvalidQueryError whether err is ErrInvalidQuery or not.
func IsInvalidQueryError(err error) bool {
return xerrors.Is(err, ErrInvalidQuery)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.12
require (
github.com/fatih/color v1.10.0
github.com/go-playground/validator/v10 v10.4.1
github.com/google/go-cmp v0.5.9
github.com/mattn/go-colorable v0.1.8
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
Expand Down
Loading

0 comments on commit 1564006

Please sign in to comment.