From 6270c29f546259b9d5e8957cc49c49179a0a7dc4 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Sun, 7 Dec 2025 20:26:01 +1100 Subject: [PATCH] Fixed processing of nested data --- pkg/yqlib/decoder_hcl.go | 29 ++++++++++++++--------------- pkg/yqlib/hcl_test.go | 14 +++++++++++++- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/pkg/yqlib/decoder_hcl.go b/pkg/yqlib/decoder_hcl.go index bf54c8ac..597eb5c9 100644 --- a/pkg/yqlib/decoder_hcl.go +++ b/pkg/yqlib/decoder_hcl.go @@ -81,14 +81,7 @@ func (dec *hclDecoder) Decode() (*CandidateNode, error) { // process blocks for _, block := range body.Blocks { - // build a key from type and labels to preserve identity - keyName := block.Type - if len(block.Labels) > 0 { - keyName = keyName + " " + strings.Join(block.Labels, " ") - } - keyNode := createStringScalarNode(keyName) - valueNode := hclBodyToNode(block.Body, dec.fileBytes) - root.AddKeyValueChild(keyNode, valueNode) + addBlockToMapping(root, block, dec.fileBytes) } dec.documentIndex++ @@ -104,17 +97,23 @@ func hclBodyToNode(body *hclsyntax.Body, src []byte) *CandidateNode { node.AddKeyValueChild(key, val) } for _, block := range body.Blocks { - keyName := block.Type - if len(block.Labels) > 0 { - keyName = keyName + " " + strings.Join(block.Labels, " ") - } - key := createStringScalarNode(keyName) - val := hclBodyToNode(block.Body, src) - node.AddKeyValueChild(key, val) + addBlockToMapping(node, block, src) } return node } +// addBlockToMapping nests block type and labels into the parent mapping, merging children. +func addBlockToMapping(parent *CandidateNode, block *hclsyntax.Block, src []byte) { + bodyNode := hclBodyToNode(block.Body, src) + chain := bodyNode + for i := len(block.Labels) - 1; i >= 0; i-- { + wrap := &CandidateNode{Kind: MappingNode} + wrap.AddKeyValueChild(createStringScalarNode(block.Labels[i]), chain) + chain = wrap + } + parent.AddKeyValueChild(createStringScalarNode(block.Type), chain) +} + func convertHclExprToNode(expr hclsyntax.Expression, src []byte) *CandidateNode { // handle literal values directly switch e := expr.(type) { diff --git a/pkg/yqlib/hcl_test.go b/pkg/yqlib/hcl_test.go index 41c43956..6bf377e5 100644 --- a/pkg/yqlib/hcl_test.go +++ b/pkg/yqlib/hcl_test.go @@ -6,6 +6,12 @@ import ( "github.com/mikefarah/yq/v4/test" ) +var nestedExample = `service "http" "web_proxy" { + listen_addr = "127.0.0.1:8080" +}` + +var nestedExampleYaml = "service:\n http:\n web_proxy:\n listen_addr: \"127.0.0.1:8080\"\n" + var hclFormatScenarios = []formatScenario{ { description: "Simple decode", @@ -25,6 +31,12 @@ var hclFormatScenarios = []formatScenario{ expected: "io_mode = async\n", scenarioType: "roundtrip", }, + { + description: "Nested decode", + input: nestedExample, + expected: nestedExampleYaml, + scenarioType: "decode", + }, { description: "Template decode", input: `message = "Hello, ${name}!"`, @@ -124,7 +136,7 @@ var hclFormatScenarios = []formatScenario{ { description: "block with labels", input: `resource "aws_instance" "example" { ami = "ami-12345" }`, - expected: "resource aws_instance example:\n ami: \"ami-12345\"\n", + expected: "resource:\n aws_instance:\n example:\n ami: \"ami-12345\"\n", scenarioType: "decode", }, {