Skip to content

fix: make strip_string_quotes yield values, not broken source (#308, #310) - #313

Open
livingstaccato wants to merge 1 commit into
amplify-education:mainfrom
livingstaccato:fix/strip-string-quotes
Open

fix: make strip_string_quotes yield values, not broken source (#308, #310)#313
livingstaccato wants to merge 1 commit into
amplify-education:mainfrom
livingstaccato:fix/strip-string-quotes

Conversation

@livingstaccato

Copy link
Copy Markdown

Fixes #310. Fixes #308.

strip_string_quotes is documented as returning a plain string instead of '"hello"', and docs/06_migrating_to_v8.md presents it as the v7 compatibility path. It did neither job completely, and both defects live in the same method.

It unquoted strings inside expressions (#310)

The option stripped every string literal, including those nested in an expression, where the surrounding text is HCL source rather than a value:

source before after
upper("x") ${upper(x)} ${upper("x")}
var.x ? "yes" : "no" ${var.x ? yes : no} ${var.x ? "yes" : "no"}
[for s in l : s if s != ""] ${[for s in l : s if s != ]} ${[for s in l : s if s != ""]}

The first two silently change meaning, referring to identifiers that do not exist; the third is not parseable at all. The fix restricts stripping to strings that are values, using the inside_dollar_string flag the serializer already threads through expression rules.

It left escapes unresolved (#308)

Asking for the value of "line1\nline2" returned a literal backslash and an n. v7 stripped quotes and resolved escapes in the same call; v8 did only the first half, so the option delivered neither the source form nor the value. Since it is already documented as one-way and not round-trippable, resolving escapes there costs nothing in reconstruction fidelity.

The pass is single, so an escaped backslash cannot combine with the character after it: \\n is a backslash followed by "n". v7 replaced sequentially and produced a backslash followed by a newline; the single pass matches what OpenTofu evaluates the same source to, so this is deliberately not bug-compatible with v7.

Only literal STRING_CHARS parts are processed. Interpolations and escaped interpolation markers carry expression text, whose escapes are not the string's to resolve.

Scope

Default output is untouched — it stays source-shaped so dumps() can reconstruct it.

Existing coverage exercised the option only on simple values, which is why neither defect showed up. Without the source change, 10 of the new tests fail. nose2 --config tox.ini: 1419 tests, OK. ruff clean.


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.

…y-education#308, amplify-education#310)

`strip_string_quotes` is documented as the option that returns a plain
string instead of `'"hello"'`, and the v8 migration guide presents it as
the v7 compatibility path. It did neither job completely.

It unquoted every string literal, including those nested inside an
expression, where the surrounding text is HCL source rather than a value:

    upper("x")                  ->  ${upper(x)}
    var.x ? "yes" : "no"        ->  ${var.x ? yes : no}
    [for s in l : s if s != ""] ->  ${[for s in l : s if s != ]}

The first two silently change meaning, referring to identifiers that do
not exist, and the third is not parseable at all. Restrict the stripping
to strings that are values, using the `inside_dollar_string` context flag
the serializer already threads through expression rules.

It also left escape sequences unresolved, so a caller asking for the
value of `"line1\nline2"` got a literal backslash and an `n`. Resolve
them when stripping, as v7 did. The pass is single, so an escaped
backslash cannot combine with the character after it -- v7 replaced
sequentially and turned `\\n` into a backslash followed by a newline,
where HCL specifies a backslash followed by "n". Only literal
STRING_CHARS parts are processed; interpolations and escaped
interpolation markers carry expression text, whose escapes are not this
string's to resolve.

Default output is untouched: it stays source-shaped so that dumps() can
reconstruct it, and this option is already documented as one-way.

Existing coverage exercised the option only on simple values, which is
why neither defect showed up. Without the fix, 10 of the new tests fail.
@livingstaccato
livingstaccato requested a review from a team as a code owner August 18, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant