Skip to content

Commit df42721

Browse files
authored
Ensure inferred project has up to date program when it might contain the requested file (microsoft#2608)
1 parent 10cc19f commit df42721

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

internal/project/projectcollectionbuilder.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ func (b *ProjectCollectionBuilder) DidRequestFile(uri lsproto.DocumentUri, logge
365365
if result.Value() != nil {
366366
if hasChanges {
367367
b.cleanupInferredProject(logger)
368+
if b.inferredProject.Value() != nil {
369+
b.updateProgram(b.inferredProject, logger)
370+
}
368371
}
369372
return
370373
}

internal/project/projectcollectionbuilder_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,52 @@ func TestProjectCollectionBuilder(t *testing.T) {
514514
session.DidOpenFile(context.Background(), "file:///script.ts", 1, files["/script.ts"].(string), lsproto.LanguageKindTypeScript)
515515
// Test should terminate
516516
})
517+
518+
t.Run("file moves to inferred project after import is deleted", func(t *testing.T) {
519+
t.Parallel()
520+
// This test verifies that when a node_modules dependency file is open and its import
521+
// is deleted from the project root, requesting language service for the dependency
522+
// correctly moves it to an inferred project.
523+
files := map[string]any{
524+
"/project/tsconfig.json": `{"compilerOptions": {"strict": true}}`,
525+
"/project/index.ts": `import { helper } from "./node_modules/dep/index";`,
526+
"/project/node_modules/dep/index.d.ts": `export declare function helper(): void;`,
527+
}
528+
session, _ := projecttestutil.Setup(files)
529+
530+
// Step 1: Open the project root file
531+
rootUri := lsproto.DocumentUri("file:///project/index.ts")
532+
session.DidOpenFile(context.Background(), rootUri, 1, files["/project/index.ts"].(string), lsproto.LanguageKindTypeScript)
533+
_, err := session.GetLanguageService(context.Background(), rootUri)
534+
assert.NilError(t, err)
535+
536+
// Step 2: Open the node_modules dependency file - should be in the configured project
537+
depUri := lsproto.DocumentUri("file:///project/node_modules/dep/index.d.ts")
538+
session.DidOpenFile(context.Background(), depUri, 1, files["/project/node_modules/dep/index.d.ts"].(string), lsproto.LanguageKindTypeScript)
539+
540+
snapshot, release := session.Snapshot()
541+
configuredProject := snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/project/tsconfig.json"))
542+
assert.Assert(t, configuredProject != nil, "configured project should exist")
543+
defaultProject := snapshot.GetDefaultProject(depUri)
544+
assert.Equal(t, defaultProject, configuredProject, "dependency should be in the configured project initially")
545+
release()
546+
547+
// Step 3: Delete the import from the root file
548+
session.DidChangeFile(context.Background(), rootUri, 2, []lsproto.TextDocumentContentChangePartialOrWholeDocument{{
549+
WholeDocument: &lsproto.TextDocumentContentChangeWholeDocument{Text: `// import removed`},
550+
}})
551+
552+
// Step 4: Request language service for the dependency - it should now be in an inferred project
553+
ls, err := session.GetLanguageService(context.Background(), depUri)
554+
assert.NilError(t, err)
555+
assert.Assert(t, ls != nil, "language service should be available for dependency")
556+
557+
snapshot, release = session.Snapshot()
558+
defer release()
559+
defaultProject = snapshot.GetDefaultProject(depUri)
560+
assert.Assert(t, defaultProject != nil, "dependency should have a default project")
561+
assert.Equal(t, defaultProject.Kind, project.KindInferred, "dependency should be in an inferred project after import is deleted")
562+
})
517563
}
518564

519565
func filesForSolutionConfigFile(solutionRefs []string, compilerOptions string, ownFiles []string) map[string]any {

0 commit comments

Comments
 (0)