|
1 | 1 | """Reconstruct HCL2 text from a Lark Tree AST.""" |
| 2 | + |
2 | 3 | from typing import List, Optional, Union |
3 | 4 |
|
4 | 5 | from lark import Tree, Token |
5 | 6 | from hcl2.rules import tokens |
6 | 7 | from hcl2.rules.base import BlockRule |
7 | 8 | from hcl2.rules.containers import ObjectElemRule |
| 9 | +from hcl2.rules.directives import ( |
| 10 | + TemplateIfRule, |
| 11 | + TemplateForRule, |
| 12 | + TemplateIfStartRule, |
| 13 | + TemplateElseRule, |
| 14 | + TemplateEndifRule, |
| 15 | + TemplateForStartRule, |
| 16 | + TemplateEndforRule, |
| 17 | +) |
8 | 18 | from hcl2.rules.for_expressions import ForIntroRule, ForTupleExprRule, ForObjectExprRule |
9 | 19 | from hcl2.rules.literal_rules import IdentifierRule |
10 | 20 | from hcl2.rules.strings import StringRule |
@@ -34,6 +44,16 @@ class HCLReconstructor: |
34 | 44 | "PLUS", |
35 | 45 | } |
36 | 46 |
|
| 47 | + _directive_rule_names = { |
| 48 | + TemplateIfStartRule.lark_name(), |
| 49 | + TemplateElseRule.lark_name(), |
| 50 | + TemplateEndifRule.lark_name(), |
| 51 | + TemplateForStartRule.lark_name(), |
| 52 | + TemplateEndforRule.lark_name(), |
| 53 | + TemplateIfRule.lark_name(), |
| 54 | + TemplateForRule.lark_name(), |
| 55 | + } |
| 56 | + |
37 | 57 | def __init__(self): |
38 | 58 | self._last_was_space = True |
39 | 59 | self._current_indent = 0 |
@@ -100,6 +120,41 @@ def _should_add_space_before( |
100 | 120 | return False |
101 | 121 | return True |
102 | 122 |
|
| 123 | + # Template directive spacing: %{~ keyword ~} patterns |
| 124 | + if parent_rule_name in self._directive_rule_names: |
| 125 | + # Space after DIRECTIVE_START (before keyword or strip marker) |
| 126 | + if self._last_token_name == tokens.DIRECTIVE_START.lark_name(): |
| 127 | + # No space before strip marker |
| 128 | + if token_type == tokens.STRIP_MARKER.lark_name(): |
| 129 | + return False |
| 130 | + return True |
| 131 | + # Space after STRIP_MARKER (before keyword) |
| 132 | + if self._last_token_name == tokens.STRIP_MARKER.lark_name(): |
| 133 | + # After strip marker: space before keyword, no space before RBRACE |
| 134 | + if token_type == tokens.RBRACE.lark_name(): |
| 135 | + return False |
| 136 | + return True |
| 137 | + # Space after keywords |
| 138 | + if self._last_token_name in [ |
| 139 | + tokens.FOR.lark_name(), |
| 140 | + tokens.IN.lark_name(), |
| 141 | + tokens.IF.lark_name(), |
| 142 | + ]: |
| 143 | + return True |
| 144 | + # Space before IN keyword (after identifier) |
| 145 | + if token_type == tokens.IN.lark_name(): |
| 146 | + return True |
| 147 | + # Space before STRIP_MARKER (before closing }) |
| 148 | + if token_type == tokens.STRIP_MARKER.lark_name(): |
| 149 | + return True |
| 150 | + # Space before RBRACE (closing directive, no strip marker) |
| 151 | + if token_type == tokens.RBRACE.lark_name(): |
| 152 | + return True |
| 153 | + # Space after COMMA in for directives |
| 154 | + if self._last_token_name == tokens.COMMA.lark_name(): |
| 155 | + return True |
| 156 | + return False |
| 157 | + |
103 | 158 | if token_type in [ |
104 | 159 | tokens.FOR.lark_name(), |
105 | 160 | tokens.IN.lark_name(), |
|
0 commit comments