diff --git a/pkg/yqlib/decoder_toml.go b/pkg/yqlib/decoder_toml.go index 984c0ad0..dd568bea 100644 --- a/pkg/yqlib/decoder_toml.go +++ b/pkg/yqlib/decoder_toml.go @@ -157,13 +157,30 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNod func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error) { content := make([]*CandidateNode, 0) + var pendingArrayComments []string + iterator := tomlNode.Children() for iterator.Next() { child := iterator.Node() + + // Handle comments within arrays + if child.Kind == toml.Comment { + // Collect comments to attach to the next array element + pendingArrayComments = append(pendingArrayComments, string(child.Data)) + continue + } + yamlNode, err := dec.decodeNode(child) if err != nil { return nil, err } + + // Attach any pending comments to this array element + if len(pendingArrayComments) > 0 { + yamlNode.HeadComment = strings.Join(pendingArrayComments, "\n") + pendingArrayComments = make([]string, 0) + } + content = append(content, yamlNode) } diff --git a/pkg/yqlib/encoder_toml.go b/pkg/yqlib/encoder_toml.go index e788cc73..b4ccc287 100644 --- a/pkg/yqlib/encoder_toml.go +++ b/pkg/yqlib/encoder_toml.go @@ -222,6 +222,81 @@ func (te *tomlEncoder) writeArrayAttribute(w io.Writer, key string, seq *Candida return err } + // Check if any array elements have head comments - if so, use multiline format + hasElementComments := false + for _, it := range seq.Content { + if it.HeadComment != "" { + hasElementComments = true + break + } + } + + if hasElementComments { + // Write multiline array format with comments + if _, err := w.Write([]byte(key + " = [\n")); err != nil { + return err + } + + for i, it := range seq.Content { + // Write head comment for this element + if it.HeadComment != "" { + commentLines := strings.Split(it.HeadComment, "\n") + for _, commentLine := range commentLines { + if strings.TrimSpace(commentLine) != "" { + if !strings.HasPrefix(strings.TrimSpace(commentLine), "#") { + commentLine = "# " + commentLine + } + if _, err := w.Write([]byte(" " + commentLine + "\n")); err != nil { + return err + } + } + } + } + + // Write the element value + var itemStr string + switch it.Kind { + case ScalarNode: + itemStr = te.formatScalar(it) + case SequenceNode: + nested, err := te.sequenceToInlineArray(it) + if err != nil { + return err + } + itemStr = nested + case MappingNode: + inline, err := te.mappingToInlineTable(it) + if err != nil { + return err + } + itemStr = inline + case AliasNode: + return fmt.Errorf("aliases are not supported in TOML") + default: + return fmt.Errorf("unsupported array item kind: %v", it.Kind) + } + + // Always add trailing comma in multiline arrays + itemStr += "," + + if _, err := w.Write([]byte(" " + itemStr + "\n")); err != nil { + return err + } + + // Add blank line between elements (except after the last one) + if i < len(seq.Content)-1 { + if _, err := w.Write([]byte("\n")); err != nil { + return err + } + } + } + + if _, err := w.Write([]byte("]\n")); err != nil { + return err + } + return nil + } + // Join scalars or nested arrays recursively into TOML array syntax items := make([]string, 0, len(seq.Content)) for _, it := range seq.Content { diff --git a/pkg/yqlib/toml_test.go b/pkg/yqlib/toml_test.go index 395a69d8..fe542a01 100644 --- a/pkg/yqlib/toml_test.go +++ b/pkg/yqlib/toml_test.go @@ -271,6 +271,16 @@ var subArrays = ` [[array.subarray.subsubarray]] ` +var tomlTableWithComments = `[section] +the_array = [ + # comment + "value 1", + + # comment + "value 2", +] +` + var expectedSubArrays = `array: - subarray: - subsubarray: @@ -598,6 +608,12 @@ var tomlScenarios = []formatScenario{ expected: sampleFromWeb, scenarioType: "roundtrip", }, + { + skipDoc: true, + input: tomlTableWithComments, + expected: tomlTableWithComments, + scenarioType: "roundtrip", + }, } func testTomlScenario(t *testing.T, s formatScenario) {