fix(parser): treat a line comment after ':' as leading, not trailing#23515
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Merging this PR will not alter performance
Comparing Footnotes
|
Monitor OxcCommit:
|
|
This is correct, I think. We handle cases like this the same as in the formatter. |
Merge activity
|
…23515) ## Summary A line comment immediately after a `:` on the same line was treated as a *trailing* comment in `should_be_treated_as_trailing_comment`, which anchors it to position `0` and drops it during codegen. The `=` and `(` tokens were already exempted from this rule for the same reason; `:` was not. This surfaced as a transformer **idempotency** failure (caught by [monitor-oxc](https://github.com/oxc-project/monitor-oxc/actions/runs/27659196490/job/81800055426)): lowering optional chaining emits `? void 0 : // comment\n_obj.method()`, so the leading comment of the original expression lands right after the `:`. Codegen kept it on the first pass but dropped it on re-parse, so `transform(transform(x)) != transform(x)`. Treating such a comment as **leading** anchors it to the following operand — preserving it and restoring idempotency. Comments after `:` in switch cases and labeled statements are likewise no longer dropped. (Object-property values and type-annotation colons are unaffected: still printed where they already were, and verified idempotent.) ## Example Input: ```js x = cond ? a : // c b; ``` Before this PR the comment was dropped (`x = cond ? a : b;`); now it is preserved. ## Tests - `leading_comments_after_colon` (`oxc_parser`) — the comment anchors to the following token. - `test_line_comment_after_conditional_colon` (`oxc_codegen`) — exact output + idempotency, including the lowered optional-chaining shape. - Verified idempotent across every `:` context (ternary, object value, switch case, label, TS type annotation); no committed transform-conformance fixture contains the affected pattern, so no snapshots change.
bc19750 to
837a395
Compare
### 💥 BREAKING CHANGES - 7a76cd3 estree: [**BREAKING**] Make whether to include TS fields a runtime option (#23574) (overlookmotel) - e7b6b68 estree: [**BREAKING**] `ESTree` config use methods not consts (#23573) (overlookmotel) ### 🚀 Features - 556cc6d data_structures: Add `CodeBuffer::as_str` method (#23571) (overlookmotel) - 38c4b06 parser: Add friendly error for adjacent JSX elements (#23378) (sapphi-red) - 53509a8 minifier: Treeshake pure typed arrays and Set/Map array literals (#23469) (Dunqing) - 09762d9 minifier: Inline const value for read-only vars (#22593) (Dunqing) ### 🐛 Bug Fixes - 20375f9 react_compiler: Keep imports referenced only by a computed key (#23586) (Boshen) - 31bfd9b minifier: Keep Object introspection calls on a possible Proxy (#23483) (Dunqing) - 837a395 parser: Treat a line comment after ':' as leading, not trailing (#23515) (Dunqing) - e409fe0 minifier: Keep `new Map`/`WeakSet`/`WeakMap` with a string argument (#23470) (Dunqing) - ae02b4e ci/parser: Use `minimal` for vitest reporter (#23457) (camc314) ### ⚡ Performance - cf24329 mangler: Compile slot sort once instead of per CAPACITY (#23577) (Boshen) - 4058a6a parser: Reduce code bloat from verify_modifiers monomorphization (#23576) (Boshen) - 053b0c1 estree: Remove pointless `mem::take` (#23572) (overlookmotel) - dfb52b6 transformer: Pre-size statement vecs in TS enum & namespace lowering (#23516) (Yunfei He) - 970e09a minifier: Compute template-literal inline checks in a single pass (#23467) (Yunfei He) - 3170c0e semantic,mangler,minifier: Fix `Semantic::stats` node count and reuse stats in mangler builds (#23352) (Boshen) - d1fa6e0 minifier: Evaluate ternary branches once in minimize_conditional_expression (#23479) (Yunfei He) - 3fa8051 transformer: Pre-size JSX props vec to attribute count (#23466) (Yunfei He) - 488b382 react_compiler: Borrow binding names in prefilter instead of allocating (#23471) (Yunfei He) - bcb3894 minifier: Incremental scoping refresh, delete LiveUsageCollector (#23197) (Dunqing) ### 📚 Documentation - f68641e data_structures: Improve docs on safety contract (#23575) (overlookmotel) Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
…23515) ## Summary A line comment immediately after a `:` on the same line was treated as a *trailing* comment in `should_be_treated_as_trailing_comment`, which anchors it to position `0` and drops it during codegen. The `=` and `(` tokens were already exempted from this rule for the same reason; `:` was not. This surfaced as a transformer **idempotency** failure (caught by [monitor-oxc](https://github.com/oxc-project/monitor-oxc/actions/runs/27659196490/job/81800055426)): lowering optional chaining emits `? void 0 : // comment\n_obj.method()`, so the leading comment of the original expression lands right after the `:`. Codegen kept it on the first pass but dropped it on re-parse, so `transform(transform(x)) != transform(x)`. Treating such a comment as **leading** anchors it to the following operand — preserving it and restoring idempotency. Comments after `:` in switch cases and labeled statements are likewise no longer dropped. (Object-property values and type-annotation colons are unaffected: still printed where they already were, and verified idempotent.) ## Example Input: ```js x = cond ? a : // c b; ``` Before this PR the comment was dropped (`x = cond ? a : b;`); now it is preserved. ## Tests - `leading_comments_after_colon` (`oxc_parser`) — the comment anchors to the following token. - `test_line_comment_after_conditional_colon` (`oxc_codegen`) — exact output + idempotency, including the lowered optional-chaining shape. - Verified idempotent across every `:` context (ternary, object value, switch case, label, TS type annotation); no committed transform-conformance fixture contains the affected pattern, so no snapshots change.
### 💥 BREAKING CHANGES - 7a76cd3 estree: [**BREAKING**] Make whether to include TS fields a runtime option (#23574) (overlookmotel) - e7b6b68 estree: [**BREAKING**] `ESTree` config use methods not consts (#23573) (overlookmotel) ### 🚀 Features - 556cc6d data_structures: Add `CodeBuffer::as_str` method (#23571) (overlookmotel) - 38c4b06 parser: Add friendly error for adjacent JSX elements (#23378) (sapphi-red) - 53509a8 minifier: Treeshake pure typed arrays and Set/Map array literals (#23469) (Dunqing) - 09762d9 minifier: Inline const value for read-only vars (#22593) (Dunqing) ### 🐛 Bug Fixes - 20375f9 react_compiler: Keep imports referenced only by a computed key (#23586) (Boshen) - 31bfd9b minifier: Keep Object introspection calls on a possible Proxy (#23483) (Dunqing) - 837a395 parser: Treat a line comment after ':' as leading, not trailing (#23515) (Dunqing) - e409fe0 minifier: Keep `new Map`/`WeakSet`/`WeakMap` with a string argument (#23470) (Dunqing) - ae02b4e ci/parser: Use `minimal` for vitest reporter (#23457) (camc314) ### ⚡ Performance - cf24329 mangler: Compile slot sort once instead of per CAPACITY (#23577) (Boshen) - 4058a6a parser: Reduce code bloat from verify_modifiers monomorphization (#23576) (Boshen) - 053b0c1 estree: Remove pointless `mem::take` (#23572) (overlookmotel) - dfb52b6 transformer: Pre-size statement vecs in TS enum & namespace lowering (#23516) (Yunfei He) - 970e09a minifier: Compute template-literal inline checks in a single pass (#23467) (Yunfei He) - 3170c0e semantic,mangler,minifier: Fix `Semantic::stats` node count and reuse stats in mangler builds (#23352) (Boshen) - d1fa6e0 minifier: Evaluate ternary branches once in minimize_conditional_expression (#23479) (Yunfei He) - 3fa8051 transformer: Pre-size JSX props vec to attribute count (#23466) (Yunfei He) - 488b382 react_compiler: Borrow binding names in prefilter instead of allocating (#23471) (Yunfei He) - bcb3894 minifier: Incremental scoping refresh, delete LiveUsageCollector (#23197) (Dunqing) ### 📚 Documentation - f68641e data_structures: Improve docs on safety contract (#23575) (overlookmotel) Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>

Summary
A line comment immediately after a
:on the same line was treated as a trailing comment inshould_be_treated_as_trailing_comment, which anchors it to position0and drops it during codegen. The=and(tokens were already exempted from this rule for the same reason;:was not.This surfaced as a transformer idempotency failure (caught by monitor-oxc): lowering optional chaining emits
? void 0 : // comment\n_obj.method(), so the leading comment of the original expression lands right after the:. Codegen kept it on the first pass but dropped it on re-parse, sotransform(transform(x)) != transform(x).Treating such a comment as leading anchors it to the following operand — preserving it and restoring idempotency. Comments after
:in switch cases and labeled statements are likewise no longer dropped. (Object-property values and type-annotation colons are unaffected: still printed where they already were, and verified idempotent.)Example
Input:
Before this PR the comment was dropped (
x = cond ? a : b;); now it is preserved.Tests
leading_comments_after_colon(oxc_parser) — the comment anchors to the following token.test_line_comment_after_conditional_colon(oxc_codegen) — exact output + idempotency, including the lowered optional-chaining shape.:context (ternary, object value, switch case, label, TS type annotation); no committed transform-conformance fixture contains the affected pattern, so no snapshots change.