Skip to content

Commit 89ad71c

Browse files
authored
Improve string escaping for HCL interpolation (#224)
Revised `_escape_interpolated_str` to handle heredoc strings and added more robust escaping for special characters. Added test HCL file to validate various unicode and complex string scenarios, ensuring accurate handling and output.
1 parent d3fe70c commit 89ad71c

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

hcl2/reconstructor.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,21 @@ def _name_to_identifier(name: str) -> Tree:
353353

354354
@staticmethod
355355
def _escape_interpolated_str(interp_s: str) -> str:
356-
# begin by doing basic JSON string escaping, to add backslashes
357-
interp_s = json.dumps(interp_s)
358-
356+
if interp_s.strip().startswith('<<-') or interp_s.strip().startswith('<<'):
357+
# For heredoc strings, preserve their format exactly
358+
return reverse_quotes_within_interpolation(interp_s)
359+
# Escape backslashes first (very important to do this first)
360+
escaped = interp_s.replace('\\', '\\\\')
361+
# Escape quotes
362+
escaped = escaped.replace('"', '\\"')
363+
# Escape control characters
364+
escaped = escaped.replace('\n', '\\n')
365+
escaped = escaped.replace('\r', '\\r')
366+
escaped = escaped.replace('\t', '\\t')
367+
escaped = escaped.replace('\b', '\\b')
368+
escaped = escaped.replace('\f', '\\f')
359369
# find each interpolation within the string and remove the backslashes
360-
interp_s = reverse_quotes_within_interpolation(interp_s)
370+
interp_s = reverse_quotes_within_interpolation(f'"{escaped}"')
361371
return interp_s
362372

363373
@staticmethod
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"locals": [
3+
{
4+
"basic_unicode": "Hello, 世界! こんにちは Привет नमस्ते",
5+
"unicode_escapes": "© ♥ ♪ ☠ ☺",
6+
"emoji_string": "🚀 🌍 🔥 🎉",
7+
"rtl_text": "English and العربية text mixed",
8+
"complex_unicode": "Python (파이썬) es 很棒的! ♥ αβγδ",
9+
"ascii": "ASCII: abc123",
10+
"emoji": "Emoji: 🚀🌍🔥🎉",
11+
"math": "Math: ∑∫√∞≠≤≥",
12+
"currency": "Currency: £€¥₹₽₩",
13+
"arrows": "Arrows: ←↑→↓↔↕",
14+
"cjk": "CJK: 你好世界안녕하세요こんにちは",
15+
"cyrillic": "Cyrillic: Привет мир",
16+
"special": "Special: ©®™§¶†‡",
17+
"mixed_content": "Line with interpolation: ${var.name}\nLine with emoji: 👨‍👩‍👧‍👦\nLine with quotes: \"quoted text\"\nLine with backslash: \\escaped"
18+
}
19+
]
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
locals {
2+
basic_unicode = "Hello, 世界! こんにちは Привет नमस्ते"
3+
unicode_escapes = "© ♥ ♪ ☠ ☺"
4+
emoji_string = "🚀 🌍 🔥 🎉"
5+
rtl_text = "English and العربية text mixed"
6+
complex_unicode = "Python (파이썬) es 很棒的! ♥ αβγδ"
7+
ascii = "ASCII: abc123"
8+
emoji = "Emoji: 🚀🌍🔥🎉"
9+
math = "Math: ∑∫√∞≠≤≥"
10+
currency = "Currency: £€¥₹₽₩"
11+
arrows = "Arrows: ←↑→↓↔↕"
12+
cjk = "CJK: 你好世界안녕하세요こんにちは"
13+
cyrillic = "Cyrillic: Привет мир"
14+
special = "Special: ©®™§¶†‡"
15+
mixed_content = <<-EOT
16+
Line with interpolation: ${var.name}
17+
Line with emoji: 👨‍👩‍👧‍👦
18+
Line with quotes: "quoted text"
19+
Line with backslash: \escaped
20+
EOT
21+
}

0 commit comments

Comments
 (0)