[api] Provide module resolution overrides - #64299
Andrew Branch (andrewbranch) wants to merge 10 commits into
Conversation
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>
There was a problem hiding this comment.
🟡 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
ModuleResolutionSetis 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
ModuleResolutionSetis 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.registerCallbackis 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.registerCallbackis 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.
There was a problem hiding this comment.
🟡 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
ModuleResolutionSetcreated 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.registerCallbackis 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 disposedis set only after the release request completes, so two concurrent calls todispose()both sendreleaseModuleResolutionSet; the second request then fails because the server handle is already gone. Memoize the in-flight disposal promise, asSnapshot.disposedoes, 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) |
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