fix: balance indent signals on multi-level jumps in embedded tagged templates#783
Merged
dsherret merged 1 commit intoMay 20, 2026
Conversation
…emplates When the external formatter's output transitions by more than one indent level between adjacent lines, `maybe_gen_tagged_tpl_with_external_formatter` emitted only a single `StartIndent`/`FinishIndent` signal but jumped `current_indent_level` to the new level. The end-of-template cleanup then emitted one `FinishIndent` per level, leaving the IR unbalanced and panicking dprint-core's writer with "finish_indent was called without a corresponding start_indent". For example, `html\`<a><svg ...><path/></svg></a>\`` produces lines at indent levels 0 → 2 → 1: the old code pushed one StartIndent and one FinishIndent, but cleanup pushed two more FinishIndents at the end — three finishes against two starts. Replace the single-step `if`/`else if` with `while` loops so multi-level transitions emit one signal per level. Fixes denoland/deno#29963.
This was referenced May 20, 2026
bartlomieju
added a commit
to denoland/deno
that referenced
this pull request
May 20, 2026
`deno fmt` panics with `finish_indent was called without a corresponding start_indent` when a tagged HTML/SVG template embeds content whose formatted output transitions by more than one indent level between adjacent lines. The minimal repro from #29963 is ```js console.log(html`<a><svg viewBox="0 0 16 16" width="20" height="20" fill="currentColor"> <path d="" /> </svg></a>`); ``` `markup_fmt` produces lines at indent levels 0 → 2 → 1, and `dprint-plugin-typescript`'s embedded-template path emitted only a single `StartIndent`/`FinishIndent` per transition while its end-of-template cleanup emitted one signal per remaining level, leaving the dprint IR unbalanced. The fix is in `dprint-plugin-typescript` (dprint/dprint-plugin-typescript#783) and is consumed here by bumping the pin to `=0.96.1`. A spec regression test in `tests/specs/fmt/embedded_html_multi_indent` covers the case using the exact input from the issue and asserts the expected formatted output. Closes #29963 Closes #33623 Closes #31820 Closes #30276 Closes #30980
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.
When the external formatter's output transitions by more than one indent
level between adjacent lines,
maybe_gen_tagged_tpl_with_external_formatteremitted only a single
StartIndent/FinishIndentsignal but jumpedcurrent_indent_leveldirectly to the new level. The end-of-templatecleanup (
while current_indent_level > 0 { FinishIndent }) then emittedone
FinishIndentper level, leaving the IR unbalanced and panickingdprint-core's writer with
finish_indent was called without a corresponding start_indent.For example, the input
produces lines at indent levels 0 → 2 → 1 from
markup_fmt. The old codepushed one StartIndent (for 0→2) and one FinishIndent (2→1), but cleanup
pushed two more FinishIndents (the 1→0 in the
whileloop plus thetrailing one closing the initial StartIndent) — three finishes against two
starts, which trips the assertion in
dprint-core.The fix replaces the single-step
if/else ifwithwhileloops somulti-level transitions emit one signal per level. Four regression specs
are added to
tests/specs/external_formatter/html.txtcovering theoriginal case, the same with an
${expr}placeholder, a three-levelsingle-line jump (
<a><b><svg>…), and a template with siblingmulti-level jumps. Each case panics on the existing code and passes on
the fix; the rest of the spec suite (648 tests) continues to pass.
Fixes denoland/deno#29963.