Skip to content

Commit cfe2eee

Browse files
authored
Preserve empty TOML arrays in tables (#2686)
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
1 parent 1a433d1 commit cfe2eee

2 files changed

Lines changed: 74 additions & 33 deletions

File tree

pkg/yqlib/encoder_toml.go

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,18 @@ func (te *tomlEncoder) encodeTopLevelEntry(w io.Writer, path []string, node *Can
195195
}
196196
}
197197

198+
func isTomlArrayOfTables(seq *CandidateNode) bool {
199+
if len(seq.Content) == 0 {
200+
return false
201+
}
202+
for _, it := range seq.Content {
203+
if it.Kind != MappingNode {
204+
return false
205+
}
206+
}
207+
return true
208+
}
209+
198210
func (te *tomlEncoder) writeAttribute(w io.Writer, key string, value *CandidateNode) error {
199211
te.wroteRootAttr = true // Mark that we wrote a root attribute
200212

@@ -462,15 +474,7 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand
462474
break
463475
}
464476
if v.Kind == SequenceNode {
465-
// Check if it's NOT an array of tables
466-
allMaps := true
467-
for _, it := range v.Content {
468-
if it.Kind != MappingNode {
469-
allMaps = false
470-
break
471-
}
472-
}
473-
if !allMaps {
477+
if !isTomlArrayOfTables(v) {
474478
hasAttrs = true
475479
break
476480
}
@@ -500,14 +504,7 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand
500504
}
501505
case SequenceNode:
502506
// If sequence of maps, emit [[path.k]] per element
503-
allMaps := true
504-
for _, it := range v.Content {
505-
if it.Kind != MappingNode {
506-
allMaps = false
507-
break
508-
}
509-
}
510-
if allMaps {
507+
if isTomlArrayOfTables(v) {
511508
key := tomlDottedKey(append(append([]string{}, path...), k))
512509
for _, it := range v.Content {
513510
if _, err := w.Write([]byte("[[" + key + "]]\n")); err != nil {
@@ -545,14 +542,7 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m *
545542
return err
546543
}
547544
case SequenceNode:
548-
allMaps := true
549-
for _, it := range v.Content {
550-
if it.Kind != MappingNode {
551-
allMaps = false
552-
break
553-
}
554-
}
555-
if !allMaps {
545+
if !isTomlArrayOfTables(v) {
556546
if err := te.writeArrayAttribute(w, k, v); err != nil {
557547
return err
558548
}
@@ -565,14 +555,7 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m *
565555
k := m.Content[i].Value
566556
v := m.Content[i+1]
567557
if v.Kind == SequenceNode {
568-
allMaps := true
569-
for _, it := range v.Content {
570-
if it.Kind != MappingNode {
571-
allMaps = false
572-
break
573-
}
574-
}
575-
if allMaps {
558+
if isTomlArrayOfTables(v) {
576559
dotted := tomlDottedKey(append(append([]string{}, path...), k))
577560
for _, it := range v.Content {
578561
if _, err := w.Write([]byte("[[" + dotted + "]]\n")); err != nil {

pkg/yqlib/toml_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,34 @@ address = "12 cat st"
209209
var rtEmptyArray = `A = []
210210
`
211211

212+
var rtEmptyArrayInTable = `[features]
213+
my-feature = []
214+
`
215+
216+
var rtMixedEmptyArraysInTable = `[features]
217+
my-other-feature = []
218+
my-feature = ["my-other-feature"]
219+
`
220+
221+
var yamlEmptyArrayInTable = `features:
222+
my-feature: []
223+
`
224+
225+
var expectedTomlEmptyArrayInTable = `[features]
226+
my-feature = []
227+
`
228+
229+
var yamlMixedEmptyArraysInTable = `features:
230+
my-other-feature: []
231+
my-feature:
232+
- my-other-feature
233+
`
234+
235+
var expectedTomlMixedEmptyArraysInTable = `[features]
236+
my-other-feature = []
237+
my-feature = ["my-other-feature"]
238+
`
239+
212240
var rtSampleTable = `var = "x"
213241
214242
[owner.contact]
@@ -563,6 +591,36 @@ var tomlScenarios = []formatScenario{
563591
expected: rtEmptyArray,
564592
scenarioType: "roundtrip",
565593
},
594+
{
595+
skipDoc: true,
596+
description: "Issue #2674: roundtrip empty array in table",
597+
input: rtEmptyArrayInTable,
598+
expression: ".",
599+
expected: rtEmptyArrayInTable,
600+
scenarioType: "roundtrip",
601+
},
602+
{
603+
skipDoc: true,
604+
description: "Issue #2674: roundtrip mixed empty and non-empty arrays in table",
605+
input: rtMixedEmptyArraysInTable,
606+
expression: ".",
607+
expected: rtMixedEmptyArraysInTable,
608+
scenarioType: "roundtrip",
609+
},
610+
{
611+
skipDoc: true,
612+
description: "Issue #2674: encode empty array in table",
613+
input: yamlEmptyArrayInTable,
614+
expected: expectedTomlEmptyArrayInTable,
615+
scenarioType: "encode",
616+
},
617+
{
618+
skipDoc: true,
619+
description: "Issue #2674: encode mixed empty and non-empty arrays in table",
620+
input: yamlMixedEmptyArraysInTable,
621+
expected: expectedTomlMixedEmptyArraysInTable,
622+
scenarioType: "encode",
623+
},
566624
{
567625
description: "Roundtrip: sample table",
568626
input: rtSampleTable,

0 commit comments

Comments
 (0)