Skip to content

Fix Live Debugger parenthesized arrow body instrumentation#447

Draft
watson wants to merge 1 commit into
watson/fix-nested-functions2from
watson/more-fixes
Draft

Fix Live Debugger parenthesized arrow body instrumentation#447
watson wants to merge 1 commit into
watson/fix-nested-functions2from
watson/more-fixes

Conversation

@watson

@watson watson commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What and why?

This fixes two more cases where the Live Debugger transform emitted invalid JavaScript, both in the wrapper-paren removal path for parenthesized arrow expression bodies. They are the same family as the recently fixed nested-function bugs and were found by running the transform over a large battery of adversarial inputs and re-parsing every output.

The first case is a parenthesized arrow body wrapping an instrumented function whose end abuts the closing paren — e.g. const f = (a) => ((b) => a + b); — which silently dropped the inner function's entire instrumentation suffix (return/catch/closing brace) and produced a syntax error. The second is a paren inside a comment within a parenthesized arrow body — e.g. const f = () => ((x) /* ) */); — which was mistaken for a wrapper paren and misaligned removal, again producing invalid output.

How?

The transform strips wrapper parens before converting the arrow to a block body. It did this with MagicString remove(), which clears the affected chunk's intro/outro. When an inner instrumented function had already appendRight-ed its suffix to that same offset (because the inner body abuts the closing paren with no whitespace), that suffix was discarded. This swaps remove() for update(pos, pos + 1, ''), which edits content only and preserves the appended suffix.

It also replaces the two raw paren scanners with a single comment-aware collectArrowWrapperParens helper. Only whitespace, comments, and wrapper parens can appear between the outermost paren and the body, so any / there must start a comment; skipping // and /* */ spans means parens inside comments are no longer miscounted as wrappers (regex/division cannot appear in that range, so no string/regex handling is needed).

Tests add regression cases for parenthesized inner arrows (nested, double-parenthesized, JSX, and parenthesized-object bodies) and for comment/regex bodies, plus coverage for async functions and class accessors/static members, which previously had no transform-level tests. The full live-debugger unit suite passes (234 tests).

When an expression-body arrow has a parenthesized body, the transform strips the
wrapper parens before injecting the block body. It did this with MagicString
`remove()`, which clears the chunk's intro/outro. If the body was itself an
instrumented function whose end abutted the closing paren (e.g.
`(a) => ((b) => a + b)`), the inner function had already appended its
instrumentation suffix to that offset, so `remove()` dropped it and emitted
invalid JavaScript.

Blank the wrapper parens with `update(..., '')` instead. It edits content only and
preserves the inner function's appended suffix.

Also make the wrapper-paren scanner comment-aware. It previously counted raw
`(`/`)` characters, so a paren inside a comment (e.g. `() => ((x) /* ) */)`) was
mistaken for a wrapper paren, misaligning removal and again producing invalid
JavaScript. Only whitespace, comments, and wrapper parens can appear in that
range, so any `/` must start a comment and can be skipped.

Add regression coverage for parenthesized inner arrows (nested, JSX, and object
bodies) and comment/regex bodies, plus previously untested async functions and
class accessors.

watson commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

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