Skip to content

Commit bb45050

Browse files
committed
Add cleanup code for projects and script infos
1 parent db8c64e commit bb45050

File tree

7 files changed

+485
-114
lines changed

7 files changed

+485
-114
lines changed

internal/project/ata.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func (ti *TypingsInstaller) EnqueueInstallTypingsRequest(p *Project, typingsInfo
145145
}
146146

147147
func (ti *TypingsInstaller) discoverAndInstallTypings(p *Project, typingsInfo *TypingsInfo, fileNames []string, projectRootPath string) {
148-
ti.init((p))
148+
ti.init(p)
149149

150150
cachedTypingPaths, newTypingNames, filesToWatch := DiscoverTypings(
151151
p.FS(),

internal/project/project.go

Lines changed: 99 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ func NewConfiguredProject(configFileName string, configFilePath tspath.Path, hos
170170
project.configFileName = configFileName
171171
project.configFilePath = configFilePath
172172
project.initialLoadPending = true
173+
project.pendingReload = PendingReloadFull
173174
client := host.Client()
174175
if host.IsWatchEnabled() && client != nil {
175176
project.rootFilesWatch = newWatchedFiles(project, lsproto.WatchKindChange|lsproto.WatchKindCreate|lsproto.WatchKindDelete, core.Identity, "root files")
@@ -361,6 +362,16 @@ func (p *Project) updateWatchers(ctx context.Context) {
361362
p.affectingLocationsWatch.update(ctx, affectingLocationGlobs)
362363
}
363364

365+
func (p *Project) tryInvokeWildCardDirectories(fileName string, path tspath.Path) bool {
366+
if p.kind == KindConfigured {
367+
if p.rootFileNames.Has(path) || p.parsedCommandLine.MatchesFileName(fileName) {
368+
p.SetPendingReload(PendingReloadFileNames)
369+
return true
370+
}
371+
}
372+
return false
373+
}
374+
364375
// onWatchEventForNilScriptInfo is fired for watch events that are not the
365376
// project tsconfig, and do not have a ScriptInfo for the associated file.
366377
// This could be a case of one of the following:
@@ -370,14 +381,9 @@ func (p *Project) updateWatchers(ctx context.Context) {
370381
// part of the project, e.g., a .js file in a project without --allowJs.
371382
func (p *Project) onWatchEventForNilScriptInfo(fileName string) {
372383
path := p.toPath(fileName)
373-
if p.kind == KindConfigured {
374-
if p.rootFileNames.Has(path) || p.parsedCommandLine.MatchesFileName(fileName) {
375-
p.pendingReload = PendingReloadFileNames
376-
p.markAsDirty()
377-
return
378-
}
384+
if p.tryInvokeWildCardDirectories(fileName, path) {
385+
return
379386
}
380-
381387
if _, ok := p.failedLookupsWatch.data[path]; ok {
382388
p.markAsDirty()
383389
} else if _, ok := p.affectingLocationsWatch.data[path]; ok {
@@ -429,6 +435,15 @@ func (p *Project) MarkFileAsDirty(path tspath.Path) {
429435
}
430436
}
431437

438+
func (p *Project) SetPendingReload(level PendingReload) {
439+
p.mu.Lock()
440+
defer p.mu.Unlock()
441+
if level > p.pendingReload {
442+
p.pendingReload = level
443+
p.markAsDirtyLocked()
444+
}
445+
}
446+
432447
func (p *Project) markAsDirty() {
433448
p.mu.Lock()
434449
defer p.mu.Unlock()
@@ -471,12 +486,12 @@ func (p *Project) updateGraph() bool {
471486
case PendingReloadFileNames:
472487
p.parsedCommandLine = tsoptions.ReloadFileNamesOfParsedCommandLine(p.parsedCommandLine, p.host.FS())
473488
writeFileNames = p.setRootFiles(p.parsedCommandLine.FileNames())
489+
p.pendingReload = PendingReloadNone
474490
case PendingReloadFull:
475491
if err := p.loadConfig(); err != nil {
476492
panic(fmt.Sprintf("failed to reload config: %v", err))
477493
}
478494
}
479-
p.pendingReload = PendingReloadNone
480495
}
481496

482497
oldProgramReused := p.updateProgram()
@@ -681,7 +696,7 @@ func (p *Project) extractUnresolvedImportsFromSourceFile(file *ast.SourceFile, o
681696
func (p *Project) UpdateTypingFiles(typingsInfo *TypingsInfo, typingFiles []string) {
682697
p.mu.Lock()
683698
defer p.mu.Unlock()
684-
if p.typingsInfo != typingsInfo {
699+
if p.isClosed() || p.typingsInfo != typingsInfo {
685700
return
686701
}
687702

@@ -710,6 +725,12 @@ func (p *Project) UpdateTypingFiles(typingsInfo *TypingsInfo, typingFiles []stri
710725
}
711726

712727
func (p *Project) WatchTypingLocations(files []string) {
728+
p.mu.Lock()
729+
defer p.mu.Unlock()
730+
if p.isClosed() {
731+
return
732+
}
733+
713734
client := p.host.Client()
714735
if !p.host.IsWatchEnabled() || client == nil {
715736
return
@@ -785,14 +806,9 @@ func (p *Project) RemoveFile(info *ScriptInfo, fileExists bool, detachFromProjec
785806
}
786807

787808
func (p *Project) removeFile(info *ScriptInfo, fileExists bool, detachFromProject bool) {
788-
if p.isRoot(info) {
789-
switch p.kind {
790-
case KindInferred:
791-
p.rootFileNames.Delete(info.path)
792-
p.typeAcquisition = nil
793-
case KindConfigured:
794-
p.pendingReload = PendingReloadFileNames
795-
}
809+
if p.isRoot(info) && p.kind == KindInferred {
810+
p.rootFileNames.Delete(info.path)
811+
p.typeAcquisition = nil
796812
}
797813
p.onFileAddedOrRemoved()
798814

@@ -809,27 +825,21 @@ func (p *Project) removeFile(info *ScriptInfo, fileExists bool, detachFromProjec
809825
}
810826
}
811827

812-
func (p *Project) AddRoot(info *ScriptInfo) {
828+
func (p *Project) AddInferredProjectRoot(info *ScriptInfo) {
813829
p.mu.Lock()
814830
defer p.mu.Unlock()
815-
p.addRoot(info)
816-
p.markAsDirtyLocked()
817-
}
818-
819-
func (p *Project) addRoot(info *ScriptInfo) {
831+
if p.isRoot(info) {
832+
panic("script info is already a root")
833+
}
834+
p.rootFileNames.Set(info.path, info.fileName)
835+
p.typeAcquisition = nil
820836
// !!!
821837
// if p.kind == KindInferred {
822838
// p.host.startWatchingConfigFilesForInferredProjectRoot(info.path);
823839
// // handle JS toggling
824840
// }
825-
if p.isRoot(info) {
826-
panic("script info is already a root")
827-
}
828-
p.rootFileNames.Set(info.path, info.fileName)
829-
if p.kind == KindInferred {
830-
p.typeAcquisition = nil
831-
}
832841
info.attachToProject(p)
842+
p.markAsDirtyLocked()
833843
}
834844

835845
func (p *Project) LoadConfig() error {
@@ -845,6 +855,7 @@ func (p *Project) loadConfig() error {
845855
panic("loadConfig called on non-configured project")
846856
}
847857

858+
p.pendingReload = PendingReloadNone
848859
if configFileContent, ok := p.host.FS().ReadFile(p.configFileName); ok {
849860
configDir := tspath.GetDirectoryPath(p.configFileName)
850861
tsConfigSourceFile := tsoptions.NewTsconfigSourceFileFromFilePath(p.configFileName, p.configFilePath, configFileContent)
@@ -885,38 +896,31 @@ func (p *Project) setRootFiles(rootFileNames []string) bool {
885896
var hasChanged bool
886897
newRootScriptInfos := make(map[tspath.Path]struct{}, len(rootFileNames))
887898
for _, file := range rootFileNames {
888-
scriptKind := p.getScriptKind(file)
889899
path := p.toPath(file)
890900
// !!! updateNonInferredProjectFiles uses a fileExists check, which I guess
891901
// could be needed if a watcher fails?
892-
scriptInfo := p.host.GetOrCreateScriptInfoForFile(file, path, scriptKind)
893902
newRootScriptInfos[path] = struct{}{}
894903
isAlreadyRoot := p.rootFileNames.Has(path)
895904
hasChanged = hasChanged || !isAlreadyRoot
896-
897-
if !isAlreadyRoot && scriptInfo != nil {
898-
p.addRoot(scriptInfo)
899-
if scriptInfo.isOpen {
900-
// !!!
901-
// s.removeRootOfInferredProjectIfNowPartOfOtherProject(scriptInfo)
902-
}
903-
} else if !isAlreadyRoot {
904-
p.rootFileNames.Set(path, file)
905-
}
905+
p.rootFileNames.Set(path, file)
906+
// if !isAlreadyRoot {
907+
// if scriptInfo.isOpen {
908+
// !!!s.removeRootOfInferredProjectIfNowPartOfOtherProject(scriptInfo)
909+
// }
910+
// }
906911
}
907912

908913
if p.rootFileNames.Size() > len(rootFileNames) {
909914
hasChanged = true
910915
for root := range p.rootFileNames.Keys() {
911916
if _, ok := newRootScriptInfos[root]; !ok {
912-
if info := p.host.GetScriptInfoByPath(root); info != nil {
913-
p.removeFile(info, true /*fileExists*/, true /*detachFromProject*/)
914-
} else {
915-
p.rootFileNames.Delete(root)
916-
}
917+
p.rootFileNames.Delete(root)
917918
}
918919
}
919920
}
921+
if hasChanged {
922+
p.onFileAddedOrRemoved()
923+
}
920924
return hasChanged
921925
}
922926

@@ -964,21 +968,20 @@ func (p *Project) GetFileNames(excludeFilesFromExternalLibraries bool, excludeCo
964968
}
965969

966970
func (p *Project) print(writeFileNames bool, writeFileExplanation bool, writeFileVersionAndText bool, builder *strings.Builder) string {
967-
builder.WriteString(fmt.Sprintf("Project '%s' (%s)\n", p.name, p.kind.String()))
971+
builder.WriteString(fmt.Sprintf("\nProject '%s' (%s)\n", p.name, p.kind.String()))
968972
if p.initialLoadPending {
969-
builder.WriteString("\tFiles (0) InitialLoadPending\n")
973+
builder.WriteString("\n\tFiles (0) InitialLoadPending\n")
970974
} else if p.program == nil {
971-
builder.WriteString("\tFiles (0) NoProgram\n")
975+
builder.WriteString("\n\tFiles (0) NoProgram\n")
972976
} else {
973977
sourceFiles := p.program.GetSourceFiles()
974-
builder.WriteString(fmt.Sprintf("\tFiles (%d)\n", len(sourceFiles)))
978+
builder.WriteString(fmt.Sprintf("\n\tFiles (%d)\n", len(sourceFiles)))
975979
if writeFileNames {
976980
for _, sourceFile := range sourceFiles {
977-
builder.WriteString("\t\t" + sourceFile.FileName())
981+
builder.WriteString("\n\t\t" + sourceFile.FileName())
978982
if writeFileVersionAndText {
979983
builder.WriteString(fmt.Sprintf(" %d %s", sourceFile.Version, sourceFile.Text()))
980984
}
981-
builder.WriteRune('\n')
982985
}
983986
// !!!
984987
// if writeFileExplanation {}
@@ -997,7 +1000,49 @@ func (p *Project) Logf(format string, args ...interface{}) {
9971000
}
9981001

9991002
func (p *Project) Close() {
1000-
// !!!
1003+
p.mu.Lock()
1004+
defer p.mu.Unlock()
1005+
1006+
if p.program != nil {
1007+
for _, sourceFile := range p.program.GetSourceFiles() {
1008+
p.host.DocumentRegistry().ReleaseDocument(sourceFile, p.program.GetCompilerOptions())
1009+
if scriptInfo := p.host.GetScriptInfoByPath(sourceFile.Path()); scriptInfo != nil {
1010+
scriptInfo.detachFromProject(p)
1011+
}
1012+
}
1013+
p.program = nil
1014+
} else if p.kind == KindInferred {
1015+
// Release root script infos for inferred projects.
1016+
for path := range p.rootFileNames.Keys() {
1017+
if info := p.host.GetScriptInfoByPath(path); info != nil {
1018+
info.detachFromProject(p)
1019+
}
1020+
}
1021+
}
1022+
p.rootFileNames = nil
1023+
p.parsedCommandLine = nil
1024+
p.checkerPool = nil
1025+
p.unresolvedImportsPerFile = nil
1026+
p.typingsInfo = nil
1027+
p.typingFiles = nil
1028+
1029+
// Clean up file watchers waiting for missing files
1030+
client := p.host.Client()
1031+
if p.host.IsWatchEnabled() && client != nil {
1032+
ctx := context.Background()
1033+
if p.rootFilesWatch != nil {
1034+
p.rootFilesWatch.update(ctx, nil)
1035+
}
1036+
1037+
p.failedLookupsWatch.update(ctx, nil)
1038+
p.affectingLocationsWatch.update(ctx, nil)
1039+
p.typingsFilesWatch.update(ctx, nil)
1040+
p.typingsDirectoryWatch.update(ctx, nil)
1041+
}
1042+
}
1043+
1044+
func (p *Project) isClosed() bool {
1045+
return p.rootFileNames == nil
10011046
}
10021047

10031048
func formatFileList(files []string, linePrefix string, groupSuffix string) string {

0 commit comments

Comments
 (0)