mirror of
https://github.com/mikefarah/yq.git
synced 2026-06-29 00:18:55 +00:00
Fix TOML roundtrip: use TomlInline flag instead of FlowStyle to preserve inline tables
FlowStyle affected YAML decode output (causing inline tables to appear as YAML flow mappings). Replace it with a new TOML-specific TomlInline bool on CandidateNode that: - Is set by the TOML decoder for inline tables (not FlowStyle) - Is copied by UpdateAttributesFrom so it survives DeeplyAssign merges - Is checked by the TOML encoder alongside FlowStyle (for YAML flow maps) - Has no effect on the YAML encoder, preserving existing TOML→YAML output TOML roundtrip tests are restored to their original expected values (inline tables stay inline, table sections stay as sections). Agent-Logs-Url: https://github.com/mikefarah/yq/sessions/f59bdf62-6d16-4664-991b-38eb87c9d81c Co-authored-by: mikefarah <1151925+mikefarah@users.noreply.github.com>
This commit is contained in:
parent
b99f4174ec
commit
d1ffec12e6
@ -100,6 +100,9 @@ type CandidateNode struct {
|
||||
// For formats like HCL and TOML: indicates that child entries should be emitted as separate blocks/tables
|
||||
// rather than consolidated into nested mappings (default behaviour)
|
||||
EncodeSeparate bool
|
||||
// For TOML: indicates that this mapping was originally a TOML inline table and should be
|
||||
// re-encoded as an inline table rather than a separate table section.
|
||||
TomlInline bool
|
||||
}
|
||||
|
||||
func (n *CandidateNode) CreateChild() *CandidateNode {
|
||||
@ -412,6 +415,7 @@ func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode {
|
||||
IsMapKey: n.IsMapKey,
|
||||
|
||||
EncodeSeparate: n.EncodeSeparate,
|
||||
TomlInline: n.TomlInline,
|
||||
}
|
||||
|
||||
if cloneContent {
|
||||
@ -467,6 +471,8 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
|
||||
|
||||
// Preserve EncodeSeparate flag for format-specific encoding hints
|
||||
n.EncodeSeparate = other.EncodeSeparate
|
||||
// Preserve TomlInline flag for TOML inline table round-trips
|
||||
n.TomlInline = other.TomlInline
|
||||
|
||||
// merge will pickup the style of the new thing
|
||||
// when autocreating nodes
|
||||
|
||||
@ -150,10 +150,10 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNod
|
||||
}
|
||||
|
||||
return &CandidateNode{
|
||||
Kind: MappingNode,
|
||||
Tag: "!!map",
|
||||
Style: FlowStyle,
|
||||
Content: content,
|
||||
Kind: MappingNode,
|
||||
Tag: "!!map",
|
||||
TomlInline: true,
|
||||
Content: content,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@ -153,9 +153,7 @@ yq '.' sample.toml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
[name]
|
||||
first = "Tom"
|
||||
last = "Preston-Werner"
|
||||
name = { first = "Tom", last = "Preston-Werner" }
|
||||
```
|
||||
|
||||
## Roundtrip: table section
|
||||
@ -374,10 +372,7 @@ dob = 1979-05-27T07:32:00-08:00
|
||||
enabled = true
|
||||
ports = [8000, 8001, 8002]
|
||||
data = [["delta", "phi"], [3.14]]
|
||||
|
||||
[database.temp_targets]
|
||||
cpu = 79.5
|
||||
case = 72.0
|
||||
temp_targets = { cpu = 79.5, case = 72.0 }
|
||||
|
||||
# [servers] yq can't do this one yet
|
||||
[servers.alpha]
|
||||
|
||||
@ -162,10 +162,9 @@ func (te *tomlEncoder) encodeTopLevelEntry(w io.Writer, path []string, node *Can
|
||||
// Regular array attribute
|
||||
return te.writeArrayAttribute(w, path[len(path)-1], node)
|
||||
case MappingNode:
|
||||
// Use inline table syntax only for nodes explicitly marked with flow/inline style
|
||||
// (e.g. TOML inline tables or YAML flow mappings). All other mappings become
|
||||
// readable TOML table sections.
|
||||
if node.Style&FlowStyle != 0 {
|
||||
// Use inline table syntax for nodes explicitly marked as TOML inline tables
|
||||
// or YAML flow mappings. All other mappings become readable TOML table sections.
|
||||
if node.TomlInline || node.Style&FlowStyle != 0 {
|
||||
return te.writeInlineTableAttribute(w, path[len(path)-1], node)
|
||||
}
|
||||
return te.encodeSeparateMapping(w, path, node)
|
||||
@ -428,7 +427,7 @@ func (te *tomlEncoder) writeTableHeader(w io.Writer, path []string, m *Candidate
|
||||
// It emits the table header for this mapping if it has any content, then processes children.
|
||||
func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *CandidateNode) error {
|
||||
// Check if this mapping has any non-mapping, non-array-of-tables children (i.e., attributes).
|
||||
// Flow-style (inline) mapping children also count as attributes since they render as key = { ... }.
|
||||
// TomlInline mapping children also count as attributes since they render as key = { ... }.
|
||||
hasAttrs := false
|
||||
for i := 0; i < len(m.Content); i += 2 {
|
||||
v := m.Content[i+1]
|
||||
@ -436,7 +435,7 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand
|
||||
hasAttrs = true
|
||||
break
|
||||
}
|
||||
if v.Kind == MappingNode && v.Style&FlowStyle != 0 {
|
||||
if v.Kind == MappingNode && (v.TomlInline || v.Style&FlowStyle != 0) {
|
||||
hasAttrs = true
|
||||
break
|
||||
}
|
||||
@ -598,13 +597,13 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m *
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, child mappings: flow-style (inline) ones become inline table attributes,
|
||||
// Finally, child mappings: TomlInline or flow-style ones become inline table attributes,
|
||||
// while all others are emitted as separate sub-table sections.
|
||||
for i := 0; i < len(m.Content); i += 2 {
|
||||
k := m.Content[i].Value
|
||||
v := m.Content[i+1]
|
||||
if v.Kind == MappingNode {
|
||||
if v.Style&FlowStyle != 0 {
|
||||
if v.TomlInline || v.Style&FlowStyle != 0 {
|
||||
if err := te.writeInlineTableAttribute(w, k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -182,12 +182,6 @@ var expectedSampleWithHeader = `servers:
|
||||
var rtInlineTableAttr = `name = { first = "Tom", last = "Preston-Werner" }
|
||||
`
|
||||
|
||||
// Inline tables are converted to readable table sections on encode
|
||||
var rtInlineTableAttrEncoded = `[name]
|
||||
first = "Tom"
|
||||
last = "Preston-Werner"
|
||||
`
|
||||
|
||||
var rtTableSection = `[owner.contact]
|
||||
name = "Tom"
|
||||
age = 36
|
||||
@ -269,33 +263,6 @@ ip = "10.0.0.2"
|
||||
role = "backend"
|
||||
`
|
||||
|
||||
// Inline table temp_targets is expanded to a readable sub-table when re-encoding
|
||||
var sampleFromWebEncoded = `# This is a TOML document
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
dob = 1979-05-27T07:32:00-08:00
|
||||
|
||||
[database]
|
||||
enabled = true
|
||||
ports = [8000, 8001, 8002]
|
||||
data = [["delta", "phi"], [3.14]]
|
||||
|
||||
[database.temp_targets]
|
||||
cpu = 79.5
|
||||
case = 72.0
|
||||
|
||||
# [servers] yq can't do this one yet
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
role = "frontend"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
role = "backend"
|
||||
`
|
||||
|
||||
var subArrays = `
|
||||
[[array]]
|
||||
|
||||
@ -539,7 +506,7 @@ var tomlScenarios = []formatScenario{
|
||||
description: "Roundtrip: inline table attribute",
|
||||
input: rtInlineTableAttr,
|
||||
expression: ".",
|
||||
expected: rtInlineTableAttrEncoded,
|
||||
expected: rtInlineTableAttr,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
{
|
||||
@ -638,7 +605,7 @@ var tomlScenarios = []formatScenario{
|
||||
description: "Roundtrip: sample from web",
|
||||
input: sampleFromWeb,
|
||||
expression: ".",
|
||||
expected: sampleFromWebEncoded,
|
||||
expected: sampleFromWeb,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user