Skip to content

Commit

Permalink
Fix toString for TagNode (#633)
Browse files Browse the repository at this point in the history
* fix tag encode in mapping

* support tag with map value

* fix TagNode toString

* Undo go mod change

* Undo editor auto change

* fix preceding space TagNode.String()

* fix merge

* fix lint

* improve tests

* fix anchor before tag

---------

Co-authored-by: Rangel Reale <rangelspam@gmail.com>
  • Loading branch information
LarsStegman and RangelReale authored Feb 4, 2025
1 parent d225e24 commit 81dbf26
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
16 changes: 12 additions & 4 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,10 @@ func (n *MappingValueNode) toString() string {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*AliasNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
} else if _, ok := n.Value.(*TagNode); ok {
return fmt.Sprintf("%s%s: %s", space, n.Key.String(), n.Value.String())
}

if keyComment != nil {
return fmt.Sprintf(
"%s%s: %s\n%s",
Expand Down Expand Up @@ -1741,9 +1744,7 @@ func (n *AnchorNode) AddColumn(col int) {
// String anchor to text
func (n *AnchorNode) String() string {
value := n.Value.String()
if len(strings.Split(value, "\n")) > 1 {
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
} else if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
return fmt.Sprintf("&%s\n%s", n.Name.String(), value)
Expand Down Expand Up @@ -1922,7 +1923,14 @@ func (n *TagNode) AddColumn(col int) {

// String tag to text
func (n *TagNode) String() string {
return fmt.Sprintf("%s %s", n.Start.Value, n.Value.String())
value := n.Value.String()
if s, ok := n.Value.(*SequenceNode); ok && !s.IsFlowStyle {
return fmt.Sprintf("%s\n%s", n.Start.Value, value)
} else if m, ok := n.Value.(*MappingNode); ok && !m.IsFlowStyle {
return fmt.Sprintf("%s\n%s", n.Start.Value, value)
}

return fmt.Sprintf("%s %s", n.Start.Value, value)
}

// MarshalYAML encodes to a YAML text
Expand Down
11 changes: 11 additions & 0 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,9 @@ func (e *Encoder) encodeMapItem(ctx context.Context, item MapItem, column int) (
if e.isMapNode(value) {
value.AddColumn(e.indentNum)
}
if e.isTagAndMapNode(value) {
value.AddColumn(e.indentNum)
}
return ast.MappingValue(
token.New("", "", e.pos(column)),
e.encodeString(k.Interface().(string), column),
Expand All @@ -646,6 +649,11 @@ func (e *Encoder) isMapNode(node ast.Node) bool {
return ok
}

func (e *Encoder) isTagAndMapNode(node ast.Node) bool {
tn, ok := node.(*ast.TagNode)
return ok && e.isMapNode(tn.Value)
}

func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int) ast.Node {
node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
keys := make([]interface{}, len(value.MapKeys()))
Expand All @@ -665,6 +673,9 @@ func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int
if e.isMapNode(value) {
value.AddColumn(e.indentNum)
}
if e.isTagAndMapNode(value) {
value.AddColumn(e.indentNum)
}
node.Values = append(node.Values, ast.MappingValue(
nil,
e.encodeString(fmt.Sprint(key), column),
Expand Down
41 changes: 41 additions & 0 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1739,3 +1739,44 @@ values:
t.Fatalf("failed to encode: got = %s", string(b))
}
}

func TestTagMarshalling(t *testing.T) {
tests := []struct {
name string
input string
}{
{name: "scalar", input: "a: !mytag 1"},
{name: "mapping", input: `
a: !mytag
b: 2`},
{name: "sequence", input: `
a: !mytag
- 1
- 2
- 3`},
{name: "anchor before tag", input: `
a: &anc !mytag
- 1
- 2
- 3`},
{name: "flow mapping", input: "a: !mytag {b: 2}"},
{name: "flow sequence", input: "a: !mytag [1, 2, 3]"},
{name: "explicit type", input: "a: !!timestamp test"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res, _ := parser.ParseBytes([]byte(tt.input), 0)
result, err := yaml.Marshal(res.Docs[0])
if err != nil {
t.Fatal(err)
}

expected := strings.TrimSpace(tt.input)
output := strings.TrimSpace(string(result))
if expected != output {
t.Fatalf("input is not equal to output.\n\nexpected:\n%v\n actual:\n%v", expected, output)
}
})
}
}

0 comments on commit 81dbf26

Please sign in to comment.