Skip to content

[api] Provide module resolution overrides - #64299

Draft
Andrew Branch (andrewbranch) wants to merge 10 commits into
microsoft:mainfrom
andrewbranch:api-module-resolution
Draft

Andrew Branch (andrewbranch) wants to merge 10 commits into
microsoft:mainfrom
andrewbranch:api-module-resolution

Conversation

@andrewbranch

Copy link
Copy Markdown
Member

This needs some tests for snapshot/program updates after #64204 lands, so marking as draft for now. I'll write up more description when I undraft.

Fixes #64069

Add snapshot-scoped reusable module resolvers and serializable resolution overrides for standalone resolution and createProgram.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
# Conflicts:
#	packages/typescript/src/api/async/api.ts
#	packages/typescript/src/api/proto.generated.ts
#	packages/typescript/src/api/sync/api.ts
#	packages/typescript/test/async/api.test.ts
#	packages/typescript/test/sync/api-generators.test.ts
#	packages/typescript/test/sync/api.test.ts
#	tools/gen-proto/main.go
#	tsc/internal/api/proto.go
#	tsc/internal/api/session.go
#	tsc/internal/project/refcountcache_test.go
#	tsc/internal/project/snapshot.go
#	tsc/internal/project/snapshothost.go
Cover reusable sets, changed and removed providers, repeated inline specs, and callbacks under the snapshot reconfiguration model.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercise synthetic-program reconfiguration end to end for reusable sets, changed and removed providers, repeated inline specs, and callbacks.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Public LSP integration, callback lifecycle, handle ownership, and resolution metadata have unresolved correctness issues.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds snapshot-scoped module resolution APIs and program-level resolution overrides.

Changes:

  • Adds reusable resolution sets, resolvers, callbacks, and fallback behavior.
  • Integrates overrides into compiler program creation and snapshot updates.
  • Exposes synchronous/asynchronous TypeScript APIs with tests.
File summaries
File Description
tsc/internal/project/snapshot.go Exposes snapshot resolution-host functionality.
tsc/internal/project/projectcollectionbuilder.go Applies resolution providers to synthetic projects.
tsc/internal/project/project.go Stores providers and passes them to programs.
tsc/internal/module/types.go Defines the resolution-provider interface.
tsc/internal/module/resolver.go Adds directory-based module resolution.
tsc/internal/lsp/server.go Connects API sessions for callbacks.
tsc/internal/compiler/program.go Tracks providers and resolution errors.
tsc/internal/compiler/filesparser.go Propagates resolution errors.
tsc/internal/compiler/fileloader.go Invokes resolution overrides while loading imports.
tsc/internal/api/session.go Handles new module-resolution requests and providers.
tsc/internal/api/session_module_resolution_test.go Tests resolution sets, callbacks, and programs.
tsc/internal/api/session_createprogram_test.go Updates request-conversion tests.
tsc/internal/api/server.go Initializes callback connectivity.
tsc/internal/api/proto.go Defines module-resolution protocol messages.
tsc/internal/api/module_resolution.go Implements API resolution behavior.
tools/gen-proto/main.go Generates the resolution-mode API type.
packages/typescript/test/sync/api.test.ts Tests synchronous provider reconfiguration.
packages/typescript/test/sync/api-generators.test.ts Tests generator-method parity.
packages/typescript/test/async/api.test.ts Tests asynchronous provider reconfiguration.
packages/typescript/src/api/syncChannel.ts Supports callback unregistration.
packages/typescript/src/api/sync/client.ts Registers synchronous callbacks.
packages/typescript/src/api/sync/api.ts Exposes synchronous resolution APIs.
packages/typescript/src/api/proto.generated.ts Adds generated protocol definitions.
packages/typescript/src/api/async/client.ts Registers asynchronous callbacks.
packages/typescript/src/api/async/api.ts Exposes asynchronous resolution APIs.
Review details

Suppressed comments (4)

packages/typescript/src/api/async/api.ts:265

  • A ModuleResolutionSet is scoped to the API session that created it, but this only checks disposal before serializing its numeric ID. If a set from another API instance is passed here, both sessions can have (for example) set ID 1, causing the request to silently use an unrelated resolution set. Validate that the set belongs to the current client/session before sending its ID.
    if (input instanceof ModuleResolutionSet) {
        input.ensureNotDisposed();
        return { set: input.id };

packages/typescript/src/api/sync/api.ts:282

  • A ModuleResolutionSet is scoped to the API session that created it, but this only checks disposal before serializing its numeric ID. If a set from another API instance is passed here, both sessions can have (for example) set ID 1, causing the request to silently use an unrelated resolution set. Validate that the set belongs to the current client/session before sending its ID.
    if (input instanceof ModuleResolutionSet) {
        input.ensureNotDisposed();
        return { set: input.id };

packages/typescript/src/api/async/api.ts:273

  • The disposer returned by client.registerCallback is discarded. Every snapshot creation/reconfiguration and module-resolver creation with a callback therefore leaves a handler that captures the user callback until the entire API connection closes, even after the owning snapshots are disposed. Track the disposer and unregister once no live snapshot or resolver can reference this callback.
    client.registerCallback(name, params => {

packages/typescript/src/api/sync/api.ts:290

  • The disposer returned by client.registerCallback is discarded. Every snapshot creation/reconfiguration and module-resolver creation with a callback therefore leaves a handler that captures the user callback until the entire API connection closes, even after the owning snapshots are disposed. Track the disposer and unregister once no live snapshot or resolver can reference this callback.
    client.registerCallback(name, params => {
  • Files reviewed: 25/25 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread tsc/internal/api/module_resolution.go Outdated
Comment thread packages/typescript/src/api/async/api.ts
Comment thread packages/typescript/src/api/sync/api.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Callback errors, callback lifetimes, cross-client handles, and concurrent disposal remain incorrect.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

packages/typescript/src/api/async/api.ts:268

  • This accepts a ModuleResolutionSet created by any API instance. Since set IDs are allocated per server session, passing a set from API A into API B can either report “not found” or, if B has allocated the same numeric ID, silently use B's unrelated resolutions. Validate that the set belongs to the current client before serializing its handle.
    packages/typescript/src/api/async/api.ts:283
  • The disposer returned by client.registerCallback is discarded, so every callback supplied while creating or reconfiguring programs/resolvers remains registered and retains its closure until the whole connection closes. Repeated snapshot updates therefore grow the callback registry without bound, including when the API request fails. Track the disposer with the provider's owning snapshot/resolver and unregister it once no live snapshot can use that provider.
    packages/typescript/src/api/async/api.ts:912
  • disposed is set only after the release request completes, so two concurrent calls to dispose() both send releaseModuleResolutionSet; the second request then fails because the server handle is already gone. Memoize the in-flight disposal promise, as Snapshot.dispose does, to keep disposal idempotent under concurrency.
  • Files reviewed: 25/25 changed files
  • Comments generated: 1
  • Review effort level: Balanced

changes = &LanguageServerSnapshotChanges{}
}
update, err := s.toLanguageServerSnapshotUpdate(&changes.SnapshotRequestChangesParams)
update, err := s.toLanguageServerSnapshotUpdate(ctx, &changes.SnapshotRequestChangesParams)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] No module resolution API: no counterpart to ts.resolveModuleName

2 participants