fix(formatter): break call args instead of = for hugged template assignments#21913
Open
jsmecham wants to merge 1 commit intooxc-project:mainfrom
Open
fix(formatter): break call args instead of = for hugged template assignments#21913jsmecham wants to merge 1 commit intooxc-project:mainfrom
= for hugged template assignments#21913jsmecham wants to merge 1 commit intooxc-project:mainfrom
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
d7b6bd0 to
7ba5543
Compare
…signments When the right-hand side of an assignment is a graphql/template hug call (`graphql(`...`)`, `fn(/* lang */ `...`)`, etc.) where the template was already multi-line in the source, prefer breaking the call's arguments out over breaking at `=` when the hugged form would overflow the print width. Single-line templates that get rewritten to multi-line by the embedded formatter still fall back to the unconditional hug, which lets will_break propagate to break the assignment at `=` — matching Prettier's `breakParent` behavior for embed labels. Member chains keep an unconditional hug so the surrounding group decides. Fixes oxc-project#21908 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7ba5543 to
1aadd72
Compare
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.
Summary
Fixes #21908
When a long-LHS variable declaration assigns the result of a single-template-arg call (e.g.
graphql(/* GraphQL */ `...`)), oxfmt broke at=and kept the call hugged. Prettier instead keeps the assignment on one line and breaks the call's arguments out around the template.Input
Before (incorrect)
After (matches Prettier)
Short-LHS cases stay hugged (matches Prettier):
Root cause
In
print/call_like_expression/arguments.rs, the three template-hug predicates (is_multiline_template_only_args,is_graphql_call_with_single_template_arg,is_huggable_html_embed_single_arg) emitted(template)directly with no group. The template's hard newlines made the parent assignment'sFluidgroup exceed the print width, so the assignment broke at=— even though breaking the call's args would have produced a shorter, Prettier-matching layout.In Prettier,
shouldExpandLastArgreturns true for embedded single-template args and usesconditionalGroup([hugged, hugged-with-break, allArgsBrokenOut]), so the assignment never breaks at=; the call args break instead when the hugged form overflows.Fix
Split the existing hug branch into two paths:
Always-hug (require, test calls, react hook deps) — unchanged, emits
(args)directly. These paths never deal with multiline content, so unconditional hug is still correct.Template-hug (graphql / multiline template / html embed) — when the call is the immediate RHS of a
VariableDeclaratororAssignmentExpressionand the template was already multi-line in the source, wrap the args inbest_fitting!:(template)— hugged(soft_block_indent(template))— broken-outbest_fittingacts as a "fits" boundary, so the assignment'sFluidgroup sees the args as fitting and doesn't break at=. When the hugged variant doesn't fit on the first line, the printer falls through to the broken-out variant.Single-line templates that get rewritten to multi-line by the embedded formatter still fall back to the unconditional hug, which lets
will_breakpropagate to break the assignment at=— matching Prettier'sbreakParentbehavior for embed labels.Non-assignment contexts (member chains, plain expression statements) keep the unconditional hug so the surrounding chain group decides how to break — preserving the existing
expect(content).toMatch(`...`)chain-break behavior.Tests
A new fixture
crates/oxc_formatter/tests/fixtures/js/calls/template-arg-hug.jsexercises five layout scenarios at bothprintWidth: 80andprintWidth: 100:=breakPrettier conformance: 746/753 JS, 591/601 TS — no regressions vs. main.
AI Disclosure
This PR was co-authored with Claude Code (AI assistant), as noted in the commit. The fix was reviewed, tested against the formatter test suite and full Prettier conformance suite, and verified to produce no regressions.