Skip to content

Place closing brace on its own line for comment-only blocks - #2469

Open
sarathfrancis90 wants to merge 1 commit into
beautifier:mainfrom
sarathfrancis90:fix/js-object-comment-only-closing-brace
Open

Place closing brace on its own line for comment-only blocks#2469
sarathfrancis90 wants to merge 1 commit into
beautifier:mainfrom
sarathfrancis90:fix/js-object-comment-only-closing-brace

Conversation

@sarathfrancis90

Copy link
Copy Markdown

Description

  • Source branch in your fork has meaningful name (not main)

When a block or object literal contains only block comment(s) and no other tokens, the closing brace was kept on the same line as the last comment. The output was not idempotent: beautifying the output a second time moved the brace onto its own line, so beautify(beautify(x)) !== beautify(x).

Example

Input:

var a = {/* c */}

Current output (one pass):

var a = {
    /* c */ }

Beautifying that output again yields the correct, stable result:

var a = {
    /* c */
}

Root cause

In handle_end_block, empty_braces was computed solely from last_token being the opening brace:

var empty_braces = this._flags.last_token.type === TOKEN.START_BLOCK;

Comments held in comments_before are emitted without updating last_token, so a block whose only content is a comment was treated as a genuinely empty {} and no newline was printed before the closing brace. The symmetric handle_start_block already guards this case with !next_token.comments_before; this PR applies the same guard to handle_end_block:

var empty_braces = !current_token.comments_before && this._flags.last_token.type === TOKEN.START_BLOCK;

Genuinely empty braces ({}) are unaffected and remain collapsed. The same change is applied to the Python implementation to keep the two implementations in parity.

Tests

Two regression cases were added to the shared test data (test/data/javascript/tests.js), covering both an object literal and a block statement that contain only a block comment. make ci passes locally for both the JavaScript and Python implementations.

Fixes Issue:

Before Merge Checklist

These items can be completed after PR is created.

(Check any items that are not applicable (NA) for this PR)

  • JavaScript implementation
  • Python implementation (NA if HTML beautifier)
  • Added Tests to data file(s)
  • Added command-line option(s) (NA - no new option)
  • README.md documents new feature/option(s) (NA - bug fix, no new feature/option)

When a block or object literal contains only block comment(s) and no
other tokens, the closing brace was kept on the same line as the last
comment, producing output such as:

    var a = {
        /* c */ }

This is not idempotent: running the beautifier on that output a second
time correctly moves the brace to its own line, so beautify(beautify(x))
differed from beautify(x).

The cause is in handle_end_block: empty_braces was computed solely from
last_token being the opening brace. Comments stored in comments_before
are emitted without updating last_token, so a brace-only-with-comment
block was treated as a genuinely empty {} and no newline was printed
before the closing brace. handle_start_block already guards the
symmetric case with !next_token.comments_before; this applies the same
guard to handle_end_block so the closing brace is placed on its own line
whenever the block contains comments.

Genuinely empty braces ({}) are unaffected and remain collapsed.

The change is applied to both the JavaScript and Python implementations,
with regression tests added to the shared test data.
@sarathfrancis90
sarathfrancis90 force-pushed the fix/js-object-comment-only-closing-brace branch from d9bf076 to c74061f Compare July 19, 2026 00:23
@sarathfrancis90

Copy link
Copy Markdown
Author

Rebased onto current main; make ci passes locally (js + python suites, black clean).

Quick recap since it has been a while: a block containing only comments was treated as empty in handle_end_block, so the closing brace stayed on the comment line and a second pass moved it — beautify was not idempotent there. handle_start_block already guards the symmetric case with !next_token.comments_before; I applied the same check on the end side, so genuinely empty {} still collapses as before.

No rush — just flagging that it is current again if you want to take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant