Skip to content

Commit 86e3b8e

Browse files
HCLReverseTransformer - rework logic recognizing blocks
1 parent b43ccf0 commit 86e3b8e

4 files changed

Lines changed: 26 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1616
### Fixed
1717

1818
- Issue parsing dot-accessed attribute as an object key ([#209](https://github.com/amplify-education/python-hcl2/pull/209))
19+
- Issue discarding empty lists when transforming python dictionary into Lark Tree ([#216](https://github.com/amplify-education/python-hcl2/pull/216))
1920

2021
## \[7.0.0\] - 2025-03-27
2122

hcl2/reconstructor.py

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -407,40 +407,29 @@ def _newline(self, level: int, count: int = 1) -> Tree:
407407
[Token("NL_OR_COMMENT", f"\n{' ' * level}") for _ in range(count)],
408408
)
409409

410-
# rules: the value of a block is always an array of dicts,
411-
# the key is the block type
412-
def _list_is_a_block(self, value: list) -> bool:
413-
for obj in value:
414-
if not self._dict_is_a_block(obj):
415-
return False
416-
417-
return True
418-
419-
def _dict_is_a_block(self, sub_obj: Any) -> bool:
420-
# if the list doesn't contain dictionaries, it's not a block
421-
if not isinstance(sub_obj, dict):
422-
return False
410+
def _is_block(self, value: Any) -> bool:
411+
if isinstance(value, dict):
412+
block_body = value
413+
if (
414+
"__start_line__" in block_body.keys()
415+
or "__end_line__" in block_body.keys()
416+
):
417+
return True
423418

424-
# if the sub object has "start_line" and "end_line" metadata,
425-
# the block itself is unlabeled, but it is a block
426-
if "__start_line__" in sub_obj.keys() or "__end_line__" in sub_obj.keys():
427-
return True
419+
try:
420+
# if block is labeled, actual body might be nested
421+
# pylint: disable=W0612
422+
block_label, block_body = next(iter(value.items()))
423+
except StopIteration:
424+
# no more potential labels = nothing more to check
425+
return False
428426

429-
# if the objects in the array have no metadata and more than 2 keys and
430-
# no metadata, it's just an array of objects, not a block
431-
if len(list(sub_obj)) != 1:
432-
return False
427+
return self._is_block(block_body)
433428

434-
# if the sub object has a single string key whose value is an object,
435-
# it _could_ be a labeled block... but we'd have to check if the sub
436-
# object is a block (recurse)
437-
label = list(sub_obj)[0]
438-
sub_sub_obj = sub_obj[label]
439-
if self._dict_is_a_block(sub_sub_obj):
440-
return True
429+
if isinstance(value, list):
430+
if len(value) > 0:
431+
return self._is_block(value[0])
441432

442-
# if the objects in the array have a single key whose child is not a
443-
# block, the array is just an array of objects, not a block
444433
return False
445434

446435
def _calculate_block_labels(self, block: dict) -> Tuple[List[str], dict]:
@@ -480,7 +469,7 @@ def _transform_dict_to_body(self, hcl_dict: dict, level: int) -> Tree:
480469
identifier_name = self._name_to_identifier(key)
481470

482471
# first, check whether the value is a "block"
483-
if isinstance(value, list) and self._list_is_a_block(value):
472+
if self._is_block(value):
484473
for block_v in value:
485474
block_labels, block_body_dict = self._calculate_block_labels(
486475
block_v

test/helpers/terraform-config-json/variables.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
"bar": {
4949
"baz": 1,
5050
"${(var.account)}": 2
51-
}
51+
},
52+
"tuple": ["${local.foo}"],
53+
"empty_tuple": []
5254
},
5355
{
5456
"route53_forwarding_rule_shares": "${{for forwarding_rule_key in keys(var.route53_resolver_forwarding_rule_shares) : \"${forwarding_rule_key}\" => {\"aws_account_ids\": \"${[for account_name in var.route53_resolver_forwarding_rule_shares[forwarding_rule_key].aws_account_names : module.remote_state_subaccounts.map[account_name].outputs[\"aws_account_id\"]]}\"}}}",

test/helpers/terraform-config/variables.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ locals {
1010
baz : 1
1111
(var.account) : 2
1212
}
13+
tuple = [local.foo]
14+
empty_tuple = []
1315
}
1416

1517
variable "azs" {

0 commit comments

Comments
 (0)