Skip to content

fix(formatter): break JSX && chain when final operand has leading own-line comment#21993

Closed
jsmecham wants to merge 3 commits into
oxc-project:mainfrom
jsmecham:fix/issue-21991
Closed

fix(formatter): break JSX && chain when final operand has leading own-line comment#21993
jsmecham wants to merge 3 commits into
oxc-project:mainfrom
jsmecham:fix/issue-21991

Conversation

@jsmecham

Copy link
Copy Markdown
Contributor

Summary

Fixes #21991

When a JSX && chain's final operand is a parenthesized JSX element with a leading own-line comment after ( (e.g. an inline // ... line comment, or a block comment separated from the JSX by a newline), oxfmt collapses the entire && chain onto a single line — even when the resulting line exceeds printWidth. Prettier breaks before each && so the line fits.

Input

export const A = () => (
  <div>
    {someLongConditionA &&
      someLongConditionB && ( // a much longer explanatory comment that clearly pushes the collapsed line beyond the 120 character print width
        <span>content</span>
      )}
  </div>
);

Before (incorrect — 163-char line at printWidth: 120)

export const A = () => (
  <div>
    {someLongConditionA && someLongConditionB && ( // a much longer explanatory comment that clearly pushes the collapsed line beyond the 120 character print width
      <span>content</span>
    )}
  </div>
);

After (matches Prettier)

export const A = () => (
  <div>
    {someLongConditionA &&
      someLongConditionB && ( // a much longer explanatory comment that clearly pushes the collapsed line beyond the 120 character print width
        <span>content</span>
      )}
  </div>
);

Root cause

In the binary-expression printer (binary_like_expression.rs), when the chain ends with a JSX operand, the chain is built as:

group(
  group(#logicalChain, [first, indent(tail_parts)]),
  indent_if_group_breaks(jsx_element, #logicalChain),
)

The #logicalChain group decides whether to break by running its own flat fits check on the chain operands. Leading comments on the JSX are emitted as line_suffix(comment) followed by expand_parent, but:

  • line_suffix content is zero-width during flat-mode fits measurement, so the comment doesn't push the chain past printWidth.
  • expand_parent only propagates to enclosing groups — and the #logicalChain group is a sibling of the comment (both are children of the outer wrapper), so its expand_parent never reaches the chain.

Result: the chain stays flat, the comment is queued for the end of the (now very long) line, and the printed line blows through printWidth.

Fix

Detect, when building the chain, whether the final JSX operand has a leading own-line comment via Comments::has_leading_own_line_comment. If so, mark the #logicalChain group with should_expand(true) so the chain breaks before each &&. This catches both inline // comments after ( (which always end the line) and block comments separated from the JSX by a newline.

A small helper BinaryLeftOrRightSide::operand_span_start returns the span start of the side's operand for the comment lookup.

Prettier conformance: no regressions (746/753 JS, 591/601 TS — unchanged).

AI Disclosure

This PR was co-authored with Claude Code (AI assistant), as noted in the commit. The fix was reviewed, tested against the full Prettier conformance suite, and verified to produce no regressions.

…wn-line comment

Fixes oxc-project#21991

When a JSX `&&` chain's final operand is a parenthesized JSX element with
a leading own-line comment (e.g. an inline `// ...` after `(`), the chain
group's flat `fits` check treats the comment as zero-width (it's emitted
as a `line_suffix`), so the chain stays on a single line — even when the
comment pushes the line well past `printWidth`. Prettier breaks before
each `&&` in this case.

Detect the leading own-line comment on the JSX operand and mark the
`#logicalChain` group with `should_expand(true)` so the chain breaks.
@codspeed-hq

codspeed-hq Bot commented Apr 30, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 44 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing jsmecham:fix/issue-21991 (b0f0a24) with main (5da9fda)2

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (5558219) during the generation of this report, so 5da9fda was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@camc314 camc314 added the A-formatter Area - Formatter label May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-formatter Area - Formatter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

formatter: JSX && chain collapsed past printWidth when ( has trailing inline comment

3 participants