python-hcl2 7.2.1__tar.gz → 7.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_hcl2-7.3.1/.github/workflows/dependencies_check.yml +27 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/CHANGELOG.md +12 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/PKG-INFO +3 -2
- python_hcl2-7.3.1/bin/check_deps.py +54 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/hcl2.lark +10 -9
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/reconstructor.py +69 -20
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/transformer.py +12 -6
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/version.py +2 -2
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/pyproject.toml +5 -1
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/PKG-INFO +3 -2
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/SOURCES.txt +2 -0
- python_hcl2-7.3.1/python_hcl2.egg-info/requires.txt +2 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/requirements.txt +1 -0
- python_hcl2-7.2.1/python_hcl2.egg-info/requires.txt +0 -1
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.codacy.yml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.coveragerc +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.github/CODEOWNERS +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.github/ISSUE_TEMPLATE/hcl2-parsing-error.md +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.github/workflows/codeql-analysis.yml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.github/workflows/pr_check.yml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.github/workflows/publish.yml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.gitignore +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.pre-commit-config.yaml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/.yamllint.yml +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/LICENSE +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/MANIFEST.in +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/README.md +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/bin/terraform_test +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/__init__.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/__main__.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/api.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/builder.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/const.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/parser.py +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/hcl2/py.typed +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/mypy.ini +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/pylintrc +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/dependency_links.txt +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/entry_points.txt +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/not-zip-safe +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/python_hcl2.egg-info/top_level.txt +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/reports/.gitignore +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/setup.cfg +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/test-requirements.txt +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/tox.ini +0 -0
- {python_hcl2-7.2.1 → python_hcl2-7.3.1}/tree-to-hcl2-reconstruction.md +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Dependencies Check
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
- reopened
|
|
8
|
+
- synchronize
|
|
9
|
+
paths:
|
|
10
|
+
- pyproject.toml
|
|
11
|
+
- requirements.txt
|
|
12
|
+
- scripts/check_deps.py
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
test:
|
|
16
|
+
name: Check dependencies sync between pyproject.toml and requirements.txt
|
|
17
|
+
runs-on: ubuntu-22.04
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@master
|
|
20
|
+
- name: Set up Python 3.13
|
|
21
|
+
uses: actions/setup-python@v4
|
|
22
|
+
with:
|
|
23
|
+
python-version: 3.13
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: python -m pip install --upgrade tomli
|
|
26
|
+
- name: Run script
|
|
27
|
+
run: python3 bin/check_deps.py
|
|
@@ -9,6 +9,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
9
9
|
|
|
10
10
|
- Nothing yet.
|
|
11
11
|
|
|
12
|
+
## \[7.3.1\] - 2025-07-24
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Updated pyproject.toml dependencies. Thanks, @kkorlyak ([#244](https://github.com/amplify-education/python-hcl2/pull/244))
|
|
17
|
+
|
|
18
|
+
## \[7.3.0\] - 2025-07-23
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Issue parsing interpolations and escaped interpolations in a single string. ([#239](https://github.com/amplify-education/python-hcl2/pull/239))
|
|
23
|
+
|
|
12
24
|
## \[7.2.1\] - 2025-05-16
|
|
13
25
|
|
|
14
26
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-hcl2
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.3.1
|
|
4
4
|
Summary: A parser for HCL2
|
|
5
5
|
Author-email: Amplify Education <github@amplify.com>
|
|
6
6
|
License: MIT
|
|
@@ -22,7 +22,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
22
22
|
Requires-Python: >=3.7.0
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: lark<2,>=1
|
|
25
|
+
Requires-Dist: lark<2.0,>=1.1.5
|
|
26
|
+
Requires-Dist: regex>=2024.4.16
|
|
26
27
|
Dynamic: license-file
|
|
27
28
|
|
|
28
29
|
[](https://app.codacy.com/gh/amplify-education/python-hcl2/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Used by dependencies_check.yml to verify if dependencies between pyproject.yml and requirements.txt are in sync"""
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Set
|
|
4
|
+
import difflib
|
|
5
|
+
import tomli
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_pyproject_deps() -> Set[str]:
|
|
9
|
+
with open("pyproject.toml", "rb") as f:
|
|
10
|
+
pyproject_data = tomli.load(f)
|
|
11
|
+
return set(pyproject_data.get("project", {}).get("dependencies", set()))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_requirements_deps() -> Set[str]:
|
|
15
|
+
result = set()
|
|
16
|
+
with open("requirements.txt", "r") as f:
|
|
17
|
+
for line in f:
|
|
18
|
+
line = line.strip()
|
|
19
|
+
if line and not line.startswith("#"):
|
|
20
|
+
result.add(line)
|
|
21
|
+
return result
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
|
|
26
|
+
pyproject_deps = get_pyproject_deps()
|
|
27
|
+
requirements_deps = get_requirements_deps()
|
|
28
|
+
|
|
29
|
+
pyproject_lines = list(sorted(pyproject_deps))
|
|
30
|
+
|
|
31
|
+
if pyproject_deps == requirements_deps:
|
|
32
|
+
print("All dependencies are in sync:")
|
|
33
|
+
for line in pyproject_lines:
|
|
34
|
+
print(line)
|
|
35
|
+
sys.exit(0)
|
|
36
|
+
|
|
37
|
+
print("Failed, dependencies mismatch:")
|
|
38
|
+
requirements_lines = list(sorted(requirements_deps))
|
|
39
|
+
|
|
40
|
+
diff = difflib.unified_diff(
|
|
41
|
+
pyproject_lines,
|
|
42
|
+
requirements_lines,
|
|
43
|
+
fromfile="pyproject.toml",
|
|
44
|
+
tofile="requirements.txt",
|
|
45
|
+
lineterm="",
|
|
46
|
+
)
|
|
47
|
+
for line in diff:
|
|
48
|
+
print(line)
|
|
49
|
+
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
main()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
start : body
|
|
2
2
|
body : (new_line_or_comment? (attribute | block))* new_line_or_comment?
|
|
3
3
|
attribute : identifier EQ expression
|
|
4
|
-
block : identifier (identifier |
|
|
4
|
+
block : identifier (identifier | string)* new_line_or_comment? "{" body "}"
|
|
5
5
|
new_line_or_comment: ( NL_OR_COMMENT )+
|
|
6
6
|
NL_OR_COMMENT: /\n[ \t]*/ | /#.*\n/ | /\/\/.*\n/ | /\/\*(.|\n)*?(\*\/)/
|
|
7
7
|
|
|
@@ -44,8 +44,7 @@ COLON : ":"
|
|
|
44
44
|
expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR
|
|
45
45
|
| float_lit
|
|
46
46
|
| int_lit
|
|
47
|
-
|
|
|
48
|
-
| string_with_interpolation
|
|
47
|
+
| string
|
|
49
48
|
| tuple
|
|
50
49
|
| object
|
|
51
50
|
| function_call
|
|
@@ -60,11 +59,13 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR
|
|
|
60
59
|
| for_tuple_expr
|
|
61
60
|
| for_object_expr
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
string: "\"" string_part* "\""
|
|
63
|
+
string_part: STRING_CHARS
|
|
64
|
+
| ESCAPED_INTERPOLATION
|
|
65
|
+
| interpolation
|
|
66
|
+
interpolation: "${" expression "}"
|
|
67
|
+
ESCAPED_INTERPOLATION.2: /\$\$\{[^}]*\}/
|
|
68
|
+
STRING_CHARS.1: /(?:(?!\$\$\{)(?!\$\{)[^"\\]|\\.|(?:\$(?!\$?\{)))+/
|
|
68
69
|
|
|
69
70
|
int_lit : NEGATIVE_DECIMAL? DECIMAL+ | NEGATIVE_DECIMAL+
|
|
70
71
|
!float_lit: (NEGATIVE_DECIMAL? DECIMAL+ | NEGATIVE_DECIMAL+) "." DECIMAL+ (EXP_MARK)?
|
|
@@ -77,7 +78,7 @@ EQ : /[ \t]*=(?!=|>)/
|
|
|
77
78
|
tuple : "[" (new_line_or_comment* expression new_line_or_comment* ",")* (new_line_or_comment* expression)? new_line_or_comment* "]"
|
|
78
79
|
object : "{" new_line_or_comment? (new_line_or_comment* (object_elem | (object_elem COMMA)) new_line_or_comment*)* "}"
|
|
79
80
|
object_elem : object_elem_key ( EQ | COLON ) expression
|
|
80
|
-
object_elem_key : float_lit | int_lit | identifier |
|
|
81
|
+
object_elem_key : float_lit | int_lit | identifier | string | object_elem_key_dot_accessor | object_elem_key_expression
|
|
81
82
|
object_elem_key_expression : LPAR expression RPAR
|
|
82
83
|
object_elem_key_dot_accessor : identifier (DOT identifier)+
|
|
83
84
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""A reconstructor for HCL2 implemented using Lark's experimental reconstruction functionality"""
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
import json
|
|
5
4
|
from typing import List, Dict, Callable, Optional, Union, Any, Tuple
|
|
6
5
|
|
|
7
6
|
from lark import Lark, Tree
|
|
@@ -10,6 +9,7 @@ from lark.lexer import Token, PatternStr, TerminalDef
|
|
|
10
9
|
from lark.reconstruct import Reconstructor
|
|
11
10
|
from lark.tree_matcher import is_discarded_terminal
|
|
12
11
|
from lark.visitors import Transformer_InPlace
|
|
12
|
+
from regex import regex
|
|
13
13
|
|
|
14
14
|
from hcl2.const import START_LINE_KEY, END_LINE_KEY
|
|
15
15
|
from hcl2.parser import reconstruction_parser
|
|
@@ -137,7 +137,7 @@ class HCLReconstructor(Reconstructor):
|
|
|
137
137
|
)
|
|
138
138
|
|
|
139
139
|
# pylint: disable=too-many-branches, too-many-return-statements
|
|
140
|
-
def _should_add_space(self, rule, current_terminal):
|
|
140
|
+
def _should_add_space(self, rule, current_terminal, is_block_label: bool = False):
|
|
141
141
|
"""
|
|
142
142
|
This method documents the situations in which we add space around
|
|
143
143
|
certain tokens while reconstructing the generated HCL.
|
|
@@ -155,6 +155,7 @@ class HCLReconstructor(Reconstructor):
|
|
|
155
155
|
|
|
156
156
|
This should be sufficient to make a spacing decision.
|
|
157
157
|
"""
|
|
158
|
+
|
|
158
159
|
# we don't need to add multiple spaces
|
|
159
160
|
if self._last_char_space:
|
|
160
161
|
return False
|
|
@@ -166,6 +167,14 @@ class HCLReconstructor(Reconstructor):
|
|
|
166
167
|
if self._is_equals_sign(current_terminal):
|
|
167
168
|
return True
|
|
168
169
|
|
|
170
|
+
if is_block_label and isinstance(rule, Token) and rule.value == "string":
|
|
171
|
+
if (
|
|
172
|
+
current_terminal == self._last_terminal == Terminal("DBLQUOTE")
|
|
173
|
+
or current_terminal == Terminal("DBLQUOTE")
|
|
174
|
+
and self._last_terminal == Terminal("NAME")
|
|
175
|
+
):
|
|
176
|
+
return True
|
|
177
|
+
|
|
169
178
|
# if we're in a ternary or binary operator, add space around the operator
|
|
170
179
|
if (
|
|
171
180
|
isinstance(rule, Token)
|
|
@@ -235,7 +244,7 @@ class HCLReconstructor(Reconstructor):
|
|
|
235
244
|
return True
|
|
236
245
|
|
|
237
246
|
# always add space between string literals
|
|
238
|
-
if current_terminal == Terminal("
|
|
247
|
+
if current_terminal == Terminal("STRING_CHARS"):
|
|
239
248
|
return True
|
|
240
249
|
|
|
241
250
|
# if we just opened a block, add a space, unless the block is empty
|
|
@@ -257,7 +266,7 @@ class HCLReconstructor(Reconstructor):
|
|
|
257
266
|
# preceded by a space if they're following a comma in a tuple or
|
|
258
267
|
# function arg
|
|
259
268
|
if current_terminal in [
|
|
260
|
-
Terminal("
|
|
269
|
+
Terminal("DBLQUOTE"),
|
|
261
270
|
Terminal("DECIMAL"),
|
|
262
271
|
Terminal("NAME"),
|
|
263
272
|
Terminal("NEGATIVE_DECIMAL"),
|
|
@@ -267,13 +276,15 @@ class HCLReconstructor(Reconstructor):
|
|
|
267
276
|
# the catch-all case, we're not sure, so don't add a space
|
|
268
277
|
return False
|
|
269
278
|
|
|
270
|
-
def _reconstruct(self, tree):
|
|
279
|
+
def _reconstruct(self, tree, is_block_label=False):
|
|
271
280
|
unreduced_tree = self.match_tree(tree, tree.data)
|
|
272
281
|
res = self.write_tokens.transform(unreduced_tree)
|
|
273
282
|
for item in res:
|
|
274
283
|
# any time we encounter a child tree, we recurse
|
|
275
284
|
if isinstance(item, Tree):
|
|
276
|
-
yield from self._reconstruct(
|
|
285
|
+
yield from self._reconstruct(
|
|
286
|
+
item, (unreduced_tree.data == "block" and item.data != "body")
|
|
287
|
+
)
|
|
277
288
|
|
|
278
289
|
# every leaf should be a tuple, which contains information about
|
|
279
290
|
# which terminal the leaf represents
|
|
@@ -309,7 +320,7 @@ class HCLReconstructor(Reconstructor):
|
|
|
309
320
|
self._deferred_item = None
|
|
310
321
|
|
|
311
322
|
# potentially add a space before the next token
|
|
312
|
-
if self._should_add_space(rule, terminal):
|
|
323
|
+
if self._should_add_space(rule, terminal, is_block_label):
|
|
313
324
|
yield " "
|
|
314
325
|
self._last_char_space = True
|
|
315
326
|
|
|
@@ -353,21 +364,21 @@ class HCLReverseTransformer:
|
|
|
353
364
|
|
|
354
365
|
@staticmethod
|
|
355
366
|
def _escape_interpolated_str(interp_s: str) -> str:
|
|
356
|
-
if interp_s.strip().startswith(
|
|
367
|
+
if interp_s.strip().startswith("<<-") or interp_s.strip().startswith("<<"):
|
|
357
368
|
# For heredoc strings, preserve their format exactly
|
|
358
369
|
return reverse_quotes_within_interpolation(interp_s)
|
|
359
370
|
# Escape backslashes first (very important to do this first)
|
|
360
|
-
escaped = interp_s.replace(
|
|
371
|
+
escaped = interp_s.replace("\\", "\\\\")
|
|
361
372
|
# Escape quotes
|
|
362
373
|
escaped = escaped.replace('"', '\\"')
|
|
363
374
|
# Escape control characters
|
|
364
|
-
escaped = escaped.replace(
|
|
365
|
-
escaped = escaped.replace(
|
|
366
|
-
escaped = escaped.replace(
|
|
367
|
-
escaped = escaped.replace(
|
|
368
|
-
escaped = escaped.replace(
|
|
375
|
+
escaped = escaped.replace("\n", "\\n")
|
|
376
|
+
escaped = escaped.replace("\r", "\\r")
|
|
377
|
+
escaped = escaped.replace("\t", "\\t")
|
|
378
|
+
escaped = escaped.replace("\b", "\\b")
|
|
379
|
+
escaped = escaped.replace("\f", "\\f")
|
|
369
380
|
# find each interpolation within the string and remove the backslashes
|
|
370
|
-
interp_s = reverse_quotes_within_interpolation(f
|
|
381
|
+
interp_s = reverse_quotes_within_interpolation(f"{escaped}")
|
|
371
382
|
return interp_s
|
|
372
383
|
|
|
373
384
|
@staticmethod
|
|
@@ -420,6 +431,44 @@ class HCLReverseTransformer:
|
|
|
420
431
|
[Token("NL_OR_COMMENT", f"\n{' ' * level}") for _ in range(count)],
|
|
421
432
|
)
|
|
422
433
|
|
|
434
|
+
def _build_string_rule(self, string: str, level: int = 0) -> Tree:
|
|
435
|
+
# grammar in hcl2.lark defines that a string is built of any number of string parts,
|
|
436
|
+
# each string part can be either interpolation expression, escaped interpolation string
|
|
437
|
+
# or regular string
|
|
438
|
+
# this method build hcl2 string rule based on arbitrary string,
|
|
439
|
+
# splitting such string into individual parts and building a lark tree out of them
|
|
440
|
+
#
|
|
441
|
+
result = []
|
|
442
|
+
|
|
443
|
+
pattern = regex.compile(r"(\${1,2}\{(?:[^{}]|(?R))*\})")
|
|
444
|
+
parts = [part for part in pattern.split(string) if part != ""]
|
|
445
|
+
# e.g. 'aaa$${bbb}ccc${"ddd-${eee}"}' -> ['aaa', '$${bbb}', 'ccc', '${"ddd-${eee}"}']
|
|
446
|
+
# 'aa-${"bb-${"cc-${"dd-${5 + 5}"}"}"}' -> ['aa-', '${"bb-${"cc-${"dd-${5 + 5}"}"}"}']
|
|
447
|
+
|
|
448
|
+
for part in parts:
|
|
449
|
+
if part.startswith("$${") and part.endswith("}"):
|
|
450
|
+
result.append(Token("ESCAPED_INTERPOLATION", part))
|
|
451
|
+
|
|
452
|
+
# unwrap interpolation expression and recurse into it
|
|
453
|
+
elif part.startswith("${") and part.endswith("}"):
|
|
454
|
+
part = part[2:-1]
|
|
455
|
+
if part.startswith('"') and part.endswith('"'):
|
|
456
|
+
part = part[1:-1]
|
|
457
|
+
part = self._transform_value_to_expr_term(part, level)
|
|
458
|
+
else:
|
|
459
|
+
part = Tree(
|
|
460
|
+
Token("RULE", "expr_term"),
|
|
461
|
+
[Tree(Token("RULE", "identifier"), [Token("NAME", part)])],
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
result.append(Tree(Token("RULE", "interpolation"), [part]))
|
|
465
|
+
|
|
466
|
+
else:
|
|
467
|
+
result.append(Token("STRING_CHARS", part))
|
|
468
|
+
|
|
469
|
+
result = [Tree(Token("RULE", "string_part"), [element]) for element in result]
|
|
470
|
+
return Tree(Token("RULE", "string"), result)
|
|
471
|
+
|
|
423
472
|
def _is_block(self, value: Any) -> bool:
|
|
424
473
|
if isinstance(value, dict):
|
|
425
474
|
block_body = value
|
|
@@ -485,8 +534,8 @@ class HCLReverseTransformer:
|
|
|
485
534
|
block_labels, block_body_dict = self._calculate_block_labels(
|
|
486
535
|
block_v
|
|
487
536
|
)
|
|
488
|
-
|
|
489
|
-
|
|
537
|
+
block_label_trees = [
|
|
538
|
+
self._build_string_rule(block_label, level)
|
|
490
539
|
for block_label in block_labels
|
|
491
540
|
]
|
|
492
541
|
block_body = self._transform_dict_to_body(
|
|
@@ -496,7 +545,7 @@ class HCLReverseTransformer:
|
|
|
496
545
|
# create our actual block to add to our own body
|
|
497
546
|
block = Tree(
|
|
498
547
|
Token("RULE", "block"),
|
|
499
|
-
[identifier_name] +
|
|
548
|
+
[identifier_name] + block_label_trees + [block_body],
|
|
500
549
|
)
|
|
501
550
|
children.append(block)
|
|
502
551
|
# add empty line after block
|
|
@@ -675,10 +724,10 @@ class HCLReverseTransformer:
|
|
|
675
724
|
parsed_value = attribute.children[2]
|
|
676
725
|
return parsed_value
|
|
677
726
|
|
|
678
|
-
# otherwise it's
|
|
727
|
+
# otherwise it's a string
|
|
679
728
|
return Tree(
|
|
680
729
|
Token("RULE", "expr_term"),
|
|
681
|
-
[
|
|
730
|
+
[self._build_string_rule(self._escape_interpolated_str(value), level)],
|
|
682
731
|
)
|
|
683
732
|
|
|
684
733
|
# otherwise, we don't know the type
|
|
@@ -247,7 +247,8 @@ class DictTransformer(Transformer):
|
|
|
247
247
|
raise RuntimeError(f"Invalid Heredoc token: {args[0]}")
|
|
248
248
|
|
|
249
249
|
trim_chars = "\n\t "
|
|
250
|
-
|
|
250
|
+
result = match.group(2).rstrip(trim_chars)
|
|
251
|
+
return f'"{result}"'
|
|
251
252
|
|
|
252
253
|
def heredoc_template_trim(self, args: List) -> str:
|
|
253
254
|
# See https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#template-expressions
|
|
@@ -297,12 +298,17 @@ class DictTransformer(Transformer):
|
|
|
297
298
|
# e.g. f"{2 + 2} {{2 + 2}}" == "4 {2 + 2}"
|
|
298
299
|
return f"{{{for_expr}}}"
|
|
299
300
|
|
|
300
|
-
def
|
|
301
|
-
return '"' +
|
|
301
|
+
def string(self, args: List) -> str:
|
|
302
|
+
return '"' + "".join(args) + '"'
|
|
302
303
|
|
|
303
|
-
def
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
def string_part(self, args: List) -> str:
|
|
305
|
+
value = self.to_tf_inline(args[0])
|
|
306
|
+
if value.startswith('"') and value.endswith('"'):
|
|
307
|
+
value = value[1:-1]
|
|
308
|
+
return value
|
|
309
|
+
|
|
310
|
+
def interpolation(self, args: List) -> str:
|
|
311
|
+
return '"${' + str(args[0]) + '}"'
|
|
306
312
|
|
|
307
313
|
def strip_new_line_tokens(self, args: List) -> List:
|
|
308
314
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-hcl2
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.3.1
|
|
4
4
|
Summary: A parser for HCL2
|
|
5
5
|
Author-email: Amplify Education <github@amplify.com>
|
|
6
6
|
License: MIT
|
|
@@ -22,7 +22,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
22
22
|
Requires-Python: >=3.7.0
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
|
-
Requires-Dist: lark<2,>=1
|
|
25
|
+
Requires-Dist: lark<2.0,>=1.1.5
|
|
26
|
+
Requires-Dist: regex>=2024.4.16
|
|
26
27
|
Dynamic: license-file
|
|
27
28
|
|
|
28
29
|
[](https://app.codacy.com/gh/amplify-education/python-hcl2/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
@@ -17,8 +17,10 @@ tree-to-hcl2-reconstruction.md
|
|
|
17
17
|
.github/CODEOWNERS
|
|
18
18
|
.github/ISSUE_TEMPLATE/hcl2-parsing-error.md
|
|
19
19
|
.github/workflows/codeql-analysis.yml
|
|
20
|
+
.github/workflows/dependencies_check.yml
|
|
20
21
|
.github/workflows/pr_check.yml
|
|
21
22
|
.github/workflows/publish.yml
|
|
23
|
+
bin/check_deps.py
|
|
22
24
|
bin/terraform_test
|
|
23
25
|
hcl2/__init__.py
|
|
24
26
|
hcl2/__main__.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
lark<2,>=1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|