Skip to content

feat(oxfmt): Support trailing ignore comments#19304

Merged
Dunqing merged 5 commits intooxc-project:mainfrom
alubbe:support-trailing-comments
Mar 2, 2026
Merged

feat(oxfmt): Support trailing ignore comments#19304
Dunqing merged 5 commits intooxc-project:mainfrom
alubbe:support-trailing-comments

Conversation

@alubbe
Copy link
Contributor

@alubbe alubbe commented Feb 12, 2026

Summary

Prettier supports end-of-line // prettier-ignore (undocumented but widely used), especially for long logging/debug statements.
oxfmt previously only respected suppression comments before the node, which forced extra lines and reduced readability in these cases, see #14669 (comment).

In the discussion on #16915 (comment), it was stated that the performance could be negatively impacted.

This PR is an attempt to show how it could be supported without sacrificing performance.

So you can now write lines like this, which won't be transformed:

logger({ level: 'debug', message: `Really long debugging message about how ${user} called a certain part of our application with a certain ${payload}` }); // prettier-ignore

I'm very happy to receive feedback/criticism and iterate on this PR.

Performance Notes

  • No extra AST pass.
  • No backtracking.
  • No new allocations or hash maps.
  • Reuses existing on-demand comment queries and parser metadata (is_line, is_trailing, newline flags).

Benchmarking

cargo bench -p oxc_benchmark --bench formatter --no-default-features --features compiler -- --save-baseline pr


   Compiling oxc_formatter v0.31.0 (/Users/andreaslubbe/code/oxc/crates/oxc_formatter)
   Compiling oxc_benchmark v0.0.0 (/Users/andreaslubbe/code/oxc/tasks/benchmark)
    Finished `bench` profile [optimized] target(s) in 23.62s
     Running benches/formatter.rs (target/release/deps/formatter-a2b283f388af781c)
Benchmarking formatter/RadixUIAdoptionSection.jsx: Warming up fo
Benchmarking formatter/RadixUIAdoptionSection.jsx: Collecting 10
formatter/RadixUIAdoptionSection.jsx
                        time:   [34.680 µs 34.752 µs 34.824 µs]
                        change: [−0.1831% +0.7658% +1.4018%] (p = 0.05 < 0.05)
                        Change within noise threshold.
Found 6 outliers among 100 measurements (6.00%)
  2 (2.00%) low severe
  2 (2.00%) low mild
  1 (1.00%) high mild
  1 (1.00%) high severe
Benchmarking formatter/errors.ts: Collecting 100 samples in esti
formatter/errors.ts     time:   [61.615 µs 61.727 µs 61.840 µs]
                        change: [−0.4673% −0.1798% +0.0776%] (p = 0.20 > 0.05)
                        No change in performance detected.
Found 5 outliers among 100 measurements (5.00%)
  2 (2.00%) low mild
  3 (3.00%) high mild
Benchmarking formatter/Search.tsx: Collecting 100 samples in est
formatter/Search.tsx    time:   [193.20 µs 193.46 µs 193.71 µs]
                        change: [+0.1333% +0.3976% +0.6556%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
  1 (1.00%) low severe
  2 (2.00%) low mild
  1 (1.00%) high severe
Benchmarking formatter/core.js: Collecting 100 samples in estima
formatter/core.js       time:   [202.53 µs 202.83 µs 203.15 µs]
                        change: [−0.8484% −0.4336% −0.0516%] (p = 0.03 < 0.05)
                        Change within noise threshold.
Found 4 outliers among 100 measurements (4.00%)
  2 (2.00%) low severe
  2 (2.00%) low mild
Benchmarking formatter/next.ts: Collecting 100 samples in estima
formatter/next.ts       time:   [288.66 µs 289.09 µs 289.54 µs]
                        change: [−0.4780% +0.0460% +0.5260%] (p = 0.86 > 0.05)
                        No change in performance detected.
Found 3 outliers among 100 measurements (3.00%)
  1 (1.00%) high mild
  2 (2.00%) high severe
Benchmarking formatter/index.tsx: Collecting 100 samples in esti
formatter/index.tsx     time:   [519.27 µs 519.96 µs 520.70 µs]
                        change: [−1.6068% −0.3630% +0.5398%] (p = 0.58 > 0.05)
                        No change in performance detected.
Found 7 outliers among 100 measurements (7.00%)
  1 (1.00%) low mild
  3 (3.00%) high mild
  3 (3.00%) high severe
Benchmarking formatter/handle-comments.js: Warming up for 3.0000
Benchmarking formatter/handle-comments.js: Collecting 100 sample
formatter/handle-comments.js
                        time:   [333.26 µs 333.70 µs 334.17 µs]
                        change: [+0.1965% +0.4268% +0.6624%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high severe
Benchmarking formatter/types.ts: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 7.3s, enable flat sampling, or reduce sample count to 50.
Benchmarking formatter/types.ts: Collecting 100 samples in estim
formatter/types.ts      time:   [1.1793 ms 1.1808 ms 1.1825 ms]
                        change: [+0.1914% +0.5340% +0.8613%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 5 outliers among 100 measurements (5.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  3 (3.00%) high severe
Benchmarking formatter/App.tsx: Collecting 100 samples in estima
formatter/App.tsx       time:   [5.8312 ms 5.8385 ms 5.8462 ms]
                        change: [+0.7680% +0.9831% +1.1990%] (p = 0.00 < 0.05)
                        Change within noise threshold.
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high severe

AI Disclosure

This PR was created over 2 days of trying different 5 different approaches, which both Claude Opus 4.6 and OpenAI GPT 5.3 helped with, until settling for this version of trying to combine the best parts.

Copilot AI review requested due to automatic review settings February 12, 2026 07:59
@github-actions github-actions bot added A-ast-tools Area - AST tools A-formatter Area - Formatter labels Feb 12, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for end-of-line suppression comments (e.g. // prettier-ignore and // oxfmt-ignore) so the formatter can preserve original source text for a statement even when the suppression marker appears on the same line (matching common Prettier usage and reducing diff noise).

Changes:

  • Add a comment query helper to detect suppression comments that appear as trailing end-of-line line comments.
  • Preserve original source text for suppressed statements when suppression is at end-of-line (with special handling for ExpressionStatement to remain ASI-safe).
  • Extend fixture-based snapshot coverage to include same-line suppression scenarios.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tasks/ast_tools/src/generators/formatter/format.rs Updates generator to emit inline trailing-suppression handling for Statement formatting (excluding ExpressionStatement).
crates/oxc_formatter/src/formatter/comments.rs Adds has_line_suppression_comment_at_end_of_line to detect same-line trailing suppression.
crates/oxc_formatter/src/print/mod.rs Implements ASI-safe preservation for ExpressionStatement when a same-line suppression is present.
crates/oxc_formatter/src/utils/statement_body.rs Ensures same-line suppression works for if consequents where trailing comments are handled specially.
crates/oxc_formatter/src/ast_nodes/generated/format.rs Generated output reflecting the new Statement suppression logic and required imports.
crates/oxc_formatter/tests/fixtures/js/... Adds/updates fixtures & snapshots to validate same-line suppression behavior.

@alubbe alubbe changed the title Support trailing comments feat(oxfmt): Support trailing ignore comments Feb 12, 2026
@github-actions github-actions bot added the C-enhancement Category - New feature or request label Feb 12, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Feb 12, 2026

Merging this PR will not alter performance

✅ 49 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing alubbe:support-trailing-comments (de164f6) with main (abc7e19)

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.

@Dunqing
Copy link
Member

Dunqing commented Feb 12, 2026

Hi @fisker, can I know why the trailing ignore comment is undocumented?

@Dunqing Dunqing force-pushed the support-trailing-comments branch from 0e820f1 to 4828a00 Compare February 12, 2026 11:04
@Dunqing Dunqing marked this pull request as draft February 12, 2026 11:04
@fisker
Copy link

fisker commented Feb 12, 2026

Hi @fisker, can I know why the trailing ignore comment is undocumented?

I don't know, I think it's bug (but I don't think we are going to fix), I didn't know about it util few month ago.

@fisker
Copy link

fisker commented Feb 12, 2026

Looks like intentionally prettier/prettier#671 (comment)

@Dunqing
Copy link
Member

Dunqing commented Feb 13, 2026

Looks like intentionally prettier/prettier#671 (comment)

Thank you! It looks like it just forgot to add documentation. 😅

@alubbe
Copy link
Contributor Author

alubbe commented Feb 14, 2026

In that case, would you like to review this PR? I could also add documentation to it, if you think this is could be mergeable. I could also open a PR on prettier adding documentation for it.

@Dunqing
Copy link
Member

Dunqing commented Feb 15, 2026

In that case, would you like to review this PR? I could also add documentation to it, if you think this is could be mergeable. I could also open a PR on prettier adding documentation for it.

I am on holiday right now. I will review this PR when I come back. It would be better to add documentation in Prettier first!

@alubbe alubbe marked this pull request as ready for review February 17, 2026 11:52
@overlookmotel overlookmotel removed their request for review February 17, 2026 15:44
@alubbe
Copy link
Contributor Author

alubbe commented Feb 24, 2026

Sounds great, enjoy your holiday!

Copy link
Member

@Dunqing Dunqing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works well! I pushed a commit to support trailing block ignore comment

@Dunqing Dunqing added 0-merge Merge with Graphite Merge Queue and removed 0-merge Merge with Graphite Merge Queue labels Mar 2, 2026
@graphite-app
Copy link
Contributor

graphite-app bot commented Mar 2, 2026

Merge activity

  • Mar 2, 3:42 AM UTC: @alubbe we removed the merge queue label because we could not find a Graphite account associated with your GitHub profile.

You must have a Graphite account in order to use the merge queue. Create an account and try again using this link

@Dunqing Dunqing force-pushed the support-trailing-comments branch from e9bdad2 to de164f6 Compare March 2, 2026 03:42
@Dunqing Dunqing merged commit 5141bc2 into oxc-project:main Mar 2, 2026
28 checks passed
camc314 pushed a commit that referenced this pull request Mar 2, 2026
# Oxlint
### 🚀 Features

- 2e0e1d0 linter/no-unused-vars: Add experimental fix mode controls
(off|suggestion|fix) (#19774) (camc314)
- f34f6fa linter: Introduce typeCheck config option (#19764) (camc314)
- 694be7d linter: Introduce typeAware as config options (#19614)
(camc314)
- 655c38f semantic: Add "did you mean?" suggestions to undefined name
errors (#19102) (copilot-swe-agent)
- e97a57e linter/id-length: Use serde to deserialize rule options
(#19636) (camc314)
- c4a3677 parser: Report error for initializer in ambient context
(#19187) (camc314)
- 346045a linter/id-length: Add `checkGeneric` option (#19634) (camc314)

### 🐛 Bug Fixes

- 1b7a937 linter: Correct double-comparisons fix with swapped operands
(#19846) (camc314)
- c308857 linter/consistent_type_imports: Add missing help and notes to
diagnostics (#19827) (Daniel Osmond)
- 7682e5a linter/plugins: Decode escapes in identifier tokens (#19838)
(overlookmotel)
- f368fcd linter/consistent_type_assertions: Add missing with_help and
with_note to diagnostics (#19826) (Daniel Osmond)
- 04e6223 npm: Add `preferUnplugged` for Yarn PnP compatibility (#19829)
(Boshen)
- 86d5037 linter: Add help text to no-extend-native,
no-useless-backreference (#19733) (Anthony Amaro)
- 50e8eff linter: Add .with_help() to operator-assignment,
no-nonoctal-decimal-escape (#19732) (Anthony Amaro)
- 1417bdc linter/no-wrapper-object-types: Add help messages to missing
diagnostics (#19771) (Daniel Osmond)
- 0838477 linter/ban_ts_comment: Add help and notes to missing
diagnostics (#19781) (Daniel Osmond)
- e8c77cf linter/adjacent_overload_signatures: Add missing diagnostics
(#19780) (Daniel Osmond)
- 28834ac linter/ban_types: Add missing help and note to diagnostics
(#19782) (Daniel Osmond)
- fd938d3 linter/prefer-enum-initializers: Add help messages to missing
diagnostics (#19772) (Daniel Osmond)
- eb928ee linter/no-dynamic-delete: Add help messages to missing
diagnostics (#19768) (Daniel Osmond)
- a985666 linter/no-empty-interface: Add help messages to missing
diagnostics (#19769) (Daniel Osmond)
- 2dc0ceb linter/no-extra-non-null-assertion: Add help messages to
missing diagnostics (#19770) (Daniel Osmond)
- 95d5d66 linter/no-dupe-keys: Handle `__proto__` proto setters in
(#19762) (camc314)
- 24ff0db linter/exhaustive-deps: False positive for member expressions
in IIFEs (#19751) (Dennis Chen)
- 7243a58 linter/no-use-before-define: Honor `ignoreTypeReferences` when
value and type name collisions (#19747) (Dimava)
- eefd818 linter/explicit-module-boundary-types: Add help messages to
missing diagnostics (#19736) (Daniel Osmond)
- 0440e9a linter: Add help text to no_control_regex, no_fallthrough,
no_param_reassign (#19655) (Anthony Amaro)
- e84cb2f react/display-name: Handle merged type+value context symbols
(#19608) (camc314)
- ce7e253 linter/prefer-object-from-entries: Require exact path match in
unicorn helper (#19687) (camc314)
- f5694ce estree/tokens: Reverse field order of `regex` object in tokens
(#19679) (overlookmotel)
- b2b7a55 estree/tokens: Generate tokens for files with BOM (#19535)
(overlookmotel)
- 0722721 linter/jsx-curly-brace-presence: False positive with prop &
mixed quotes (#19674) (camc314)
- 3496acd linter: Enhance diagnostic help messages for eslint rules
(#19653) (Anthony Amaro)
- e384e94 linter: Enhance help diagnostic messages for more eslint rules
(#19658) (Anthony Amaro)
- a4d5b34 linter: Avoid non-promise catch false positives (#19574)
(camc314)
- 5706f38 linter: `unicorn/no-array-callback-reference` skip `Effect.*`
array-like methods name. (#19633) (Said Atrahouch)

### ⚡ Performance

- 05ccf9f linter/plugins: Transfer tokens via raw transfer (#19893)
(overlookmotel)
- 4b0611a estree/tokens: Introduce `ESTreeTokenConfig` trait (#19842)
(overlookmotel)
- ec88f6a estree/tokens: Serialize tokens while visiting AST (#19726)
(overlookmotel)
- d4dcf26 linter/plugins: Remove `typescript` from bundle (#19531)
(overlookmotel)
- 6a6513c linter/plugins: Use Oxc tokens in plugins (#19498) (camc314)

### 📚 Documentation

- d86f59e linter: Improve docs for no-useless-concat, mark as pending
fixer. (#19859) (connorshea)
- caa091d linter/plugins: Correct doc comments for `initTokens` (#19530)
(overlookmotel)
- 2fa936f README.md: Map npm package links to npmx.dev (#19666) (Boshen)
- dc0ff73 linter/no-useless-constructor: Warn for parameter properties
as well (#19638) (Ole Asteo)
# Oxfmt
### 🚀 Features

- 5141bc2 formatter: Support trailing ignore comments (#19304) (Andreas
Lubbe)
- 4888a99 oxfmt/lsp: Support other schemes beside `file://` and
`untitled://` (#19872) (Sysix)
- 14a0181 oxfmt: Support `graphql()` variant for gql-in-js (#19703)
(leaysgur)
- ca68ea6 oxfmt: Support gql-in-js substitution (#19670) (leaysgur)
- 035933c formatter,oxfmt: Support js-in-vue (partially) (#19514)
(leaysgur)
- 9e11dc6 parser,estree,coverage: Collect tokens in parser and convert
to ESTree format (#19497) (camc314)

### 🐛 Bug Fixes

- 8e3842d oxfmt: Avoid embedded TSFN crash by returning errors as data
(take2) (#19806) (Yuji Sugiura)
- 04e6223 npm: Add `preferUnplugged` for Yarn PnP compatibility (#19829)
(Boshen)
- e540585 oxfmt: Support tailwind sort for CSS/LESS/SCSS (#19803)
(leaysgur)
- 93bb861 formatter: Trim trailing whitespace before breaking line
(#19740) (leaysgur)
- b85f97b formatter: Drop blank line between terminal call and first
chain member (#19659) (Dunqing)

### ⚡ Performance

- b3b2d30 parser: Introduce `ParserConfig` (#19637) (overlookmotel)

### 📚 Documentation

- 2fa936f README.md: Map npm package links to npmx.dev (#19666) (Boshen)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ast-tools Area - AST tools A-formatter Area - Formatter C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants