Skip to content

build: fix async private method token fusion; inlineChat: adopt native private fields#308797

Merged
jrieken merged 2 commits intomainfrom
joh/private-fields-async-fix
Apr 10, 2026
Merged

build: fix async private method token fusion; inlineChat: adopt native private fields#308797
jrieken merged 2 commits intomainfrom
joh/private-fields-async-fix

Conversation

@jrieken
Copy link
Copy Markdown
Member

@jrieken jrieken commented Apr 9, 2026

Summary

Fix async private method token fusion in the private-to-property build rewrite, and adopt native ES private fields in the inlineChat module.

Session Context

Key decisions from the development session:

  • Token fusion fix approach: When the character before # is an identifier character (e.g. async#run), the replacement is prefixed with a space (async $a instead of async$a). This is safe because an extra space in a non-minified position never changes semantics, and in minified code it's the minimal fix to prevent the $ from fusing with the preceding keyword.
  • isIdentifierChar helper: Checks a-z, A-Z, 0-9, _, $ — the characters that can continue an identifier in JS. Placed outside convertPrivateFields as a module-level utility since it's pure and stateless.
  • Test-first: The async fusion bug was first reproduced with failing tests, then fixed. Three test variants cover: minified async#method, minified static async#method, and non-minified async #method (which already had a space and passed before the fix).
  • Build-time syntax check (from prior PR): The esbuild.transform() syntax check added in the prior PR is what caught this bug during the build — it works as intended.

Changes

Commit 1: build: fix async private method token fusion

  • private-to-property.ts: When emitting a replacement for a PrivateIdentifier, check if the preceding character is an identifier char. If so, prepend a space to prevent token fusion (e.g. async#runasync $a not async$a).
  • private-to-property.ts: Add isIdentifierChar() helper.
  • test/private-to-property.test.ts: 3 new tests for async, static async, and readable async private methods.

Commit 2: inlineChat: adopt native ES private fields

  • Convert 8 inlineChat files from private _field to #field pattern.

…ewrite

In minified code, `async#method()` has no space between `async` and
`#method`. The `#` naturally starts a new token, but when replaced with
`$a`, the `$` is a valid identifier character — `async$a` fuses into
a single identifier. This makes any `await` inside the method body a
syntax error.

Fix: when the character immediately before the `#` is an identifier
character, prepend a space to the replacement text.

Add 3 tests covering async, static async, and the readable variant.
Copilot AI review requested due to automatic review settings April 9, 2026 14:49
@jrieken jrieken marked this pull request as draft April 9, 2026 14:53
Copy link
Copy Markdown
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 addresses a build-time bug in the private-field rewrite (token fusion for minified async#method patterns) and modernizes the inline chat implementation by switching from TypeScript private _field members to native ES #private fields.

Changes:

  • Fix convertPrivateFields to insert a separating space when a PrivateIdentifier follows an identifier character (prevents async$a token fusion).
  • Add/extend unit tests covering async private method minified forms.
  • Convert inline chat browser code to use native #private fields for state and injected services.
Show a summary per file
File Description
build/next/private-to-property.ts Prevents token fusion by conditionally prefixing replacements with a space based on preceding character.
build/next/test/private-to-property.test.ts Adds tests intended to cover async/static-async private method minified cases.
src/vs/workbench/contrib/inlineChat/browser/inlineChatZoneWidget.ts Migrates internal state/options/logging to native #private fields.
src/vs/workbench/contrib/inlineChat/browser/inlineChatWidget.ts Migrates widget internals and injected services to #private fields.
src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts Migrates service internals/events/session map to #private fields.
src/vs/workbench/contrib/inlineChat/browser/inlineChatOverlayWidget.ts Migrates overlay widgets’ DOM/state/history interactions to #private fields.
src/vs/workbench/contrib/inlineChat/browser/inlineChatNotebook.ts Migrates disposable store to #private field.
src/vs/workbench/contrib/inlineChat/browser/inlineChatHistoryService.ts Migrates storage/history handling to #private fields/method.
src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.ts Migrates widget state/editor refs to #private fields and methods.
src/vs/workbench/contrib/inlineChat/browser/inlineChatController.ts Migrates controller state/services and internal helpers to #private fields/methods.

Copilot's findings

  • Files reviewed: 10/10 changed files
  • Comments generated: 1

Convert inlineChat module from TypeScript private (`private _field`)
to native ES private fields (`#field`) for better encapsulation and
V8 performance (after the private-to-property build step mangles them).
@jrieken jrieken force-pushed the joh/private-fields-async-fix branch from 8f08454 to 8f9f550 Compare April 10, 2026 08:18
@jrieken jrieken added this to the 1.116.0 milestone Apr 10, 2026
@jrieken jrieken marked this pull request as ready for review April 10, 2026 08:49
@jrieken jrieken merged commit 80c19eb into main Apr 10, 2026
26 checks passed
@jrieken jrieken deleted the joh/private-fields-async-fix branch April 10, 2026 10:49
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.

3 participants