Skip to content

Commit b934886

Browse files
HCLReverseTransformer - rework logic recognizing blocks
1 parent 1e8b233 commit b934886

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
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Fixed
1111

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

1415
## \[7.0.0\] - 2025-03-27
1516

hcl2/reconstructor.py

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

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

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

423-
# if the objects in the array have no metadata and more than 2 keys and
424-
# no metadata, it's just an array of objects, not a block
425-
if len(list(sub_obj)) != 1:
426-
return False
421+
return self._is_block(block_body)
427422

428-
# if the sub object has a single string key whose value is an object,
429-
# it _could_ be a labeled block... but we'd have to check if the sub
430-
# object is a block (recurse)
431-
label = list(sub_obj)[0]
432-
sub_sub_obj = sub_obj[label]
433-
if self._dict_is_a_block(sub_sub_obj):
434-
return True
423+
if isinstance(value, list):
424+
if len(value) > 0:
425+
return self._is_block(value[0])
435426

436-
# if the objects in the array have a single key whose child is not a
437-
# block, the array is just an array of objects, not a block
438427
return False
439428

440429
def _calculate_block_labels(self, block: dict) -> Tuple[List[str], dict]:
@@ -474,7 +463,7 @@ def _transform_dict_to_body(self, hcl_dict: dict, level: int) -> Tree:
474463
identifier_name = self._name_to_identifier(key)
475464

476465
# first, check whether the value is a "block"
477-
if isinstance(value, list) and self._list_is_a_block(value):
466+
if self._is_block(value):
478467
for block_v in value:
479468
block_labels, block_body_dict = self._calculate_block_labels(
480469
block_v

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@
4747
"foo": "${var.account}_bar",
4848
"bar": {
4949
"baz": 1
50-
}
50+
},
51+
"tuple": ["${local.foo}"],
52+
"empty_tuple": []
5153
},
5254
{
5355
"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
@@ -9,6 +9,8 @@ locals {
99
bar = {
1010
baz : 1
1111
}
12+
tuple = [local.foo]
13+
empty_tuple = []
1214
}
1315

1416
variable "azs" {

0 commit comments

Comments
 (0)