11import json
22from functools import lru_cache
3- from typing import Any , TextIO , List
3+ from typing import Any , TextIO , List , Union
44
55from regex import regex
66
3131 StringRule ,
3232 InterpolationRule ,
3333 StringPartRule ,
34+ HeredocTemplateRule ,
35+ HeredocTrimTemplateRule ,
3436)
3537from hcl2 .rule_transformer .rules .tokens import (
3638 NAME ,
4749 COMMA ,
4850 DOT ,
4951 LBRACE ,
52+ HEREDOC_TRIM_TEMPLATE ,
53+ HEREDOC_TEMPLATE ,
5054)
5155from hcl2 .rule_transformer .transformer import RuleTransformer
52- from hcl2 .rule_transformer .utils import DeserializationOptions
56+ from hcl2 .rule_transformer .utils import DeserializationOptions , HEREDOC_TRIM_PATTERN , HEREDOC_PATTERN
5357
5458
5559class Deserializer :
@@ -99,7 +103,7 @@ def _deserialize_block_elements(self, value: dict) -> List[LarkRule]:
99103
100104 return children
101105
102- def _deserialize_text (self , value ) -> LarkRule :
106+ def _deserialize_text (self , value : Any ) -> LarkRule :
103107 try :
104108 int_val = int (value )
105109 return IntLitRule ([IntLiteral (int_val )])
@@ -114,6 +118,16 @@ def _deserialize_text(self, value) -> LarkRule:
114118
115119 if isinstance (value , str ):
116120 if value .startswith ('"' ) and value .endswith ('"' ):
121+ if not self .options .heredocs_to_strings and value .startswith ('"<<-' ):
122+ match = HEREDOC_TRIM_PATTERN .match (value [1 :- 1 ])
123+ if match :
124+ return self ._deserialize_heredoc (value [1 :- 1 ], True )
125+
126+ if not self .options .heredocs_to_strings and value .startswith ('"<<' ):
127+ match = HEREDOC_PATTERN .match (value [1 :- 1 ])
128+ if match :
129+ return self ._deserialize_heredoc (value [1 :- 1 ], False )
130+
117131 return self ._deserialize_string (value )
118132
119133 if self ._is_expression (value ):
@@ -131,11 +145,12 @@ def _deserialize_identifier(self, value: str) -> IdentifierRule:
131145
132146 def _deserialize_string (self , value : str ) -> StringRule :
133147 result = []
134-
135- pattern = regex .compile (r"(\${1,2}\{(?:[^{}]|(?R))*\})" )
136- parts = [part for part in pattern .split (value ) if part != "" ]
148+ # split string into individual parts based on lark grammar
137149 # e.g. 'aaa$${bbb}ccc${"ddd-${eee}"}' -> ['aaa', '$${bbb}', 'ccc', '${"ddd-${eee}"}']
138150 # 'aa-${"bb-${"cc-${"dd-${5 + 5}"}"}"}' -> ['aa-', '${"bb-${"cc-${"dd-${5 + 5}"}"}"}']
151+ pattern = regex .compile (r"(\${1,2}\{(?:[^{}]|(?R))*\})" )
152+ parts = [part for part in pattern .split (value ) if part != "" ]
153+
139154
140155 for part in parts :
141156 if part == '"' :
@@ -166,6 +181,11 @@ def _deserialize_string_part(self, value: str) -> StringPartRule:
166181
167182 return StringPartRule ([STRING_CHARS (value )])
168183
184+ def _deserialize_heredoc (self , value : str , trim : bool ) -> Union [HeredocTemplateRule , HeredocTrimTemplateRule ]:
185+ if trim :
186+ return HeredocTrimTemplateRule ([HEREDOC_TRIM_TEMPLATE (value )])
187+ return HeredocTemplateRule ([HEREDOC_TEMPLATE (value )])
188+
169189 def _deserialize_expression (self , value : str ) -> ExprTermRule :
170190 """Deserialize an expression string into an ExprTermRule."""
171191 # instead of processing expression manually and trying to recognize what kind of expression it is,
0 commit comments