From 198ac3aa438635f767c45916737c8107038d1121 Mon Sep 17 00:00:00 2001 From: James Rawlings Date: Tue, 6 Aug 2024 13:54:20 +0100 Subject: [PATCH 1/2] handle formatting of empty but not nil structs Signed-off-by: James Rawlings --- pkg/yam/format_test.go | 3 +++ pkg/yam/testdata/format/update.yaml | 6 ++++++ pkg/yam/testdata/format/update_expected.yaml | 6 ++++++ 3 files changed, 15 insertions(+) create mode 100644 pkg/yam/testdata/format/update.yaml create mode 100644 pkg/yam/testdata/format/update_expected.yaml diff --git a/pkg/yam/format_test.go b/pkg/yam/format_test.go index 5d1189c..d5c3fbf 100644 --- a/pkg/yam/format_test.go +++ b/pkg/yam/format_test.go @@ -36,6 +36,9 @@ func Test_formatSingleFile(t *testing.T) { { fixture: "testdata/format/whitespace_issues.yaml", }, + { + fixture: "testdata/format/update.yaml", + }, } for _, tt := range cases { diff --git a/pkg/yam/testdata/format/update.yaml b/pkg/yam/testdata/format/update.yaml new file mode 100644 index 0000000..ef2d76a --- /dev/null +++ b/pkg/yam/testdata/format/update.yaml @@ -0,0 +1,6 @@ +update: + enabled: true + git: {} + schedule: + daily: true + reason: upstream does not maintain tags or releases, it uses a branch diff --git a/pkg/yam/testdata/format/update_expected.yaml b/pkg/yam/testdata/format/update_expected.yaml new file mode 100644 index 0000000..ef2d76a --- /dev/null +++ b/pkg/yam/testdata/format/update_expected.yaml @@ -0,0 +1,6 @@ +update: + enabled: true + git: {} + schedule: + daily: true + reason: upstream does not maintain tags or releases, it uses a branch From 546509f93c9c31b69b12e4748325b25e51f56172 Mon Sep 17 00:00:00 2001 From: James Rawlings Date: Tue, 6 Aug 2024 21:54:11 +0100 Subject: [PATCH 2/2] fix to handle empty structs `{}` rather than formatting them and changing it to nil Signed-off-by: James Rawlings --- pkg/yam/formatted/encoder.go | 69 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/pkg/yam/formatted/encoder.go b/pkg/yam/formatted/encoder.go index 0e53123..3f8a4d8 100644 --- a/pkg/yam/formatted/encoder.go +++ b/pkg/yam/formatted/encoder.go @@ -199,6 +199,12 @@ func (enc Encoder) marshal(node *yaml.Node, nodePath path.Path) ([]byte, error) return bytes, nil case yaml.MappingNode: + // Handle empty mappings explicitly + //if len(node.Content) == 0 { + // return []byte("{}"), nil + //} + + // Marshal non-empty mappings return enc.marshalMapping(node, nodePath) case yaml.SequenceNode: @@ -212,7 +218,6 @@ func (enc Encoder) marshal(node *yaml.Node, nodePath path.Path) ([]byte, error) default: return yaml.Marshal(node) - } } @@ -221,49 +226,49 @@ func (enc Encoder) marshalMapping(node *yaml.Node, nodePath path.Path) ([]byte, var result []byte var latestKey string - for i, item := range node.Content { - if isMapKeyIndex(i) { - rawKeyBytes, err := enc.marshal(item, nodePath) - if err != nil { - return nil, err - } - - // assume the key can be a string (this isn't always true in YAML, but we'll see how far this gets us) - key := bytes.TrimSuffix(rawKeyBytes, newline) - latestKey = string(key) - - keyBytes := bytes.Join([][]byte{ - key, - colon, - }, nil) + for i := 0; i < len(node.Content); i += 2 { + keyNode := node.Content[i] + valueNode := node.Content[i+1] - if nextItem := node.Content[i+1]; nextItem.Kind == yaml.ScalarNode && nextItem.Tag != "!!null" { // TODO: check that there is a value node for this key node - // render in same line - keyBytes = append(keyBytes, space...) - } else { - keyBytes = append(keyBytes, newline...) - } + rawKeyBytes, err := enc.marshal(keyNode, nodePath) + if err != nil { + return nil, err + } - result = append(result, keyBytes...) - continue + key := bytes.TrimSuffix(rawKeyBytes, newline) + latestKey = string(key) + + keyBytes := bytes.Join([][]byte{ + key, + colon, + }, nil) + + // Check for empty mapping node and handle it + if valueNode.Kind == yaml.MappingNode && len(valueNode.Content) == 0 { + keyBytes = append(keyBytes, space...) + keyBytes = append(keyBytes, []byte("{}")...) + } else if valueNode.Kind == yaml.ScalarNode && valueNode.Tag != "!!null" { + // Render scalar values in the same line + keyBytes = append(keyBytes, space...) + } else { + keyBytes = append(keyBytes, newline...) } - nodePathForValue := nodePath.AppendMapPart(latestKey) + result = append(result, keyBytes...) - valueBytes, err := enc.marshal(item, nodePathForValue) + valueBytes, err := enc.marshal(valueNode, nodePath.AppendMapPart(latestKey)) if err != nil { return nil, err } - isFinalMapValue := i == len(node.Content)-1 + isFinalMapValue := (i + 1) == len(node.Content)-1 - // This was the key's value node, so add a gap if configured to do so. - // We shouldn't add a newline after the final map value, though. + // Avoid adding a newline after the final map value if enc.matchesAnyGapPath(nodePath) && !isFinalMapValue { valueBytes = append(valueBytes, newline...) } - if item.Kind == yaml.MappingNode || item.Kind == yaml.SequenceNode { + if valueNode.Kind == yaml.MappingNode || valueNode.Kind == yaml.SequenceNode { valueBytes = enc.applyIndent(valueBytes) } else { valueBytes = enc.handleMultilineStringIndentation(valueBytes) @@ -275,10 +280,6 @@ func (enc Encoder) marshalMapping(node *yaml.Node, nodePath path.Path) ([]byte, return result, nil } -func isMapKeyIndex(i int) bool { - return i%2 == 0 -} - func (enc Encoder) marshalSequence(node *yaml.Node, nodePath path.Path) ([]byte, error) { var lines [][]byte