fix: two rules that ignored they were writing expression source (#340, #341) - #350
Draft
livingstaccato wants to merge 1 commit into
Draft
Conversation
…ify-education#340, amplify-education#341) `inside_dollar_string` says the text being produced is part of an expression rather than a value for the caller. `StringRule` checks it and keeps its quotes, because `upper("x")` becoming `upper(x)` asks for a variable nobody declared. Two rules did not. A heredoc argument was spliced in bare: `upper(<<E\nx\nE\n)` came back as `${upper(x)}`, and a multi-line body put raw newlines into source that no longer parsed. Both heredoc rules check the flag now, in the flattened and the trimmed paths. With `preserve_heredocs` on, the heredoc is left as itself rather than wrapped in quotes. That was quoting raw newlines, which OpenTofu rejects with "Invalid multi-line string"; as a heredoc it is a legal argument and `trimspace(<<EOF\n hi \nEOF\n)` evaluates to "hi". One existing test pinned the quoted form and now states this. `TemplateStringRule` dropped its delimiters in the value form, turning `%{ if x == "y" }` into `%{ if x == y }` -- a comparison against a variable rather than a string. It only ever appears inside a directive, which is always expression source.
Contributor
Author
|
Please hold off on merging this one for now — I want to do another review pass over it before it goes in. Opened as a draft for that reason; I will mark it ready and say so here once I am done. |
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #340.
Fixes #341.
What
SerializationContext.inside_dollar_stringtells a rule that the text it is producing is part of an expression rather than a value handed to the caller.StringRulechecks it and keeps its quotes, for the obvious reason:upper("x")becomingupper(x)asks for a variable nobody declared. Two rules did not check it.#340 — a heredoc argument was spliced in bare.
The quoted equivalent one line away was already correct (
${upper("x")}). With a multi-line body it was worse: raw newlines went into expression source that then did not parse.#341 — a string literal inside a directive lost its delimiters.
TemplateStringRuleonly ever appears inside%{ ... }, where the text is expression source and the quotes belong to a literal written in it.One thing that changes beyond the issues
With
preserve_heredocson, a heredoc inside an expression is now left as itself rather than wrapped in quotes. Quoting it put raw newlines inside a quoted string, which OpenTofu rejects with "Invalid multi-line string"; as a heredoc it is a legal argument, andtrimspace(<<EOF\n hi \nEOF\n)evaluates to"hi". One existing test pinned the quoted form and now states this, with the reason.Ground truth
OpenTofu v1.12.5:
upper(<<EOT\nx\nEOT\n)evaluates to"X\n", so the argument is a string; a directive literal is written with plain quotes,"%{ if local.x == "y" }t%{ endif }", and evaluates to"t". That plain spelling round-trips here unchanged, and is asserted so it stays that way.One divergence this does not touch: the grammar accepts
\"y\"inside a directive, which OpenTofu rejects with "Invalid character". That is a separate defect, filed as #353. This PR only stops the value form from mangling that spelling into a reference; it neither blesses nor removes it.Merging
It touches the same code as #335 (
hcl2/rules/strings.py), #346 (hcl2/rules/strings.py), #352 (hcl2/rules/strings.py), #354 (hcl2/rules/strings.py). Whichever of those lands first, this one needs a rebase rather than a merge — the overlaps are real edits to the same methods, not adjacent lines, so resolving them by hand risks losing one of the two fixes. Say the word and I will rebase and re-run the suite.This pull request, and the investigation behind it, were produced by an AI assistant (Claude) working on behalf of the author. Every reproduction, test run and benchmark cited was executed rather than inferred, but please review with that provenance in mind.