@@ -284,6 +284,10 @@ namespace ts.server {
284284 configFileErrors ?: ReadonlyArray < Diagnostic > ;
285285 }
286286
287+ interface AssignProjectResult extends OpenConfiguredProjectResult {
288+ defaultConfigProject : ConfiguredProject | undefined ;
289+ }
290+
287291 interface FilePropertyReader < T > {
288292 getFileName ( f : T ) : string ;
289293 getScriptKind ( f : T , extraFileExtensions ?: FileExtensionInfo [ ] ) : ScriptKind ;
@@ -2635,10 +2639,11 @@ namespace ts.server {
26352639 return info ;
26362640 }
26372641
2638- private assignProjectToOpenedScriptInfo ( info : ScriptInfo ) : OpenConfiguredProjectResult {
2642+ private assignProjectToOpenedScriptInfo ( info : ScriptInfo ) : AssignProjectResult {
26392643 let configFileName : NormalizedPath | undefined ;
26402644 let configFileErrors : ReadonlyArray < Diagnostic > | undefined ;
26412645 let project : ConfiguredProject | ExternalProject | undefined = this . findExternalProjectContainingOpenScriptInfo ( info ) ;
2646+ let defaultConfigProject : ConfiguredProject | undefined ;
26422647 if ( ! project && ! this . syntaxOnly ) { // Checking syntaxOnly is an optimization
26432648 configFileName = this . getConfigFileNameForFile ( info ) ;
26442649 if ( configFileName ) {
@@ -2659,6 +2664,7 @@ namespace ts.server {
26592664 // Ensure project is ready to check if it contains opened script info
26602665 updateProjectIfDirty ( project ) ;
26612666 }
2667+ defaultConfigProject = project ;
26622668 }
26632669 }
26642670
@@ -2678,13 +2684,13 @@ namespace ts.server {
26782684 this . assignOrphanScriptInfoToInferredProject ( info , this . openFiles . get ( info . path ) ) ;
26792685 }
26802686 Debug . assert ( ! info . isOrphan ( ) ) ;
2681- return { configFileName, configFileErrors } ;
2687+ return { configFileName, configFileErrors, defaultConfigProject } ;
26822688 }
26832689
2684- private cleanupAfterOpeningFile ( ) {
2690+ private cleanupAfterOpeningFile ( toRetainConfigProjects : ConfiguredProject [ ] | ConfiguredProject | undefined ) {
26852691 // This was postponed from closeOpenFile to after opening next file,
26862692 // so that we can reuse the project if we need to right away
2687- this . removeOrphanConfiguredProjects ( ) ;
2693+ this . removeOrphanConfiguredProjects ( toRetainConfigProjects ) ;
26882694
26892695 // Remove orphan inferred projects now that we have reused projects
26902696 // We need to create a duplicate because we cant guarantee order after removal
@@ -2705,22 +2711,30 @@ namespace ts.server {
27052711
27062712 openClientFileWithNormalizedPath ( fileName : NormalizedPath , fileContent ?: string , scriptKind ?: ScriptKind , hasMixedContent ?: boolean , projectRootPath ?: NormalizedPath ) : OpenConfiguredProjectResult {
27072713 const info = this . getOrCreateOpenScriptInfo ( fileName , fileContent , scriptKind , hasMixedContent , projectRootPath ) ;
2708- const result = this . assignProjectToOpenedScriptInfo ( info ) ;
2709- this . cleanupAfterOpeningFile ( ) ;
2714+ const { defaultConfigProject , ... result } = this . assignProjectToOpenedScriptInfo ( info ) ;
2715+ this . cleanupAfterOpeningFile ( defaultConfigProject ) ;
27102716 this . telemetryOnOpenFile ( info ) ;
27112717 return result ;
27122718 }
27132719
2714- private removeOrphanConfiguredProjects ( ) {
2720+ private removeOrphanConfiguredProjects ( toRetainConfiguredProjects : ConfiguredProject [ ] | ConfiguredProject | undefined ) {
27152721 const toRemoveConfiguredProjects = cloneMap ( this . configuredProjects ) ;
2722+ if ( toRetainConfiguredProjects ) {
2723+ if ( isArray ( toRetainConfiguredProjects ) ) {
2724+ toRetainConfiguredProjects . forEach ( retainConfiguredProject ) ;
2725+ }
2726+ else {
2727+ retainConfiguredProject ( toRetainConfiguredProjects ) ;
2728+ }
2729+ }
27162730
27172731 // Do not remove configured projects that are used as original projects of other
27182732 this . inferredProjects . forEach ( markOriginalProjectsAsUsed ) ;
27192733 this . externalProjects . forEach ( markOriginalProjectsAsUsed ) ;
27202734 this . configuredProjects . forEach ( project => {
27212735 // If project has open ref (there are more than zero references from external project/open file), keep it alive as well as any project it references
27222736 if ( project . hasOpenRef ( ) ) {
2723- toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2737+ retainConfiguredProject ( project ) ;
27242738 markOriginalProjectsAsUsed ( project ) ;
27252739 }
27262740 else {
@@ -2729,7 +2743,7 @@ namespace ts.server {
27292743 if ( ref ) {
27302744 const refProject = this . configuredProjects . get ( ref . sourceFile . path ) ;
27312745 if ( refProject && refProject . hasOpenRef ( ) ) {
2732- toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2746+ retainConfiguredProject ( project ) ;
27332747 }
27342748 }
27352749 } ) ;
@@ -2744,6 +2758,10 @@ namespace ts.server {
27442758 project . originalConfiguredProjects . forEach ( ( _value , configuredProjectPath ) => toRemoveConfiguredProjects . delete ( configuredProjectPath ) ) ;
27452759 }
27462760 }
2761+
2762+ function retainConfiguredProject ( project : ConfiguredProject ) {
2763+ toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2764+ }
27472765 }
27482766
27492767 private removeOrphanScriptInfos ( ) {
@@ -2886,8 +2904,9 @@ namespace ts.server {
28862904 }
28872905
28882906 // All the script infos now exist, so ok to go update projects for open files
2907+ let defaultConfigProjects : ConfiguredProject [ ] | undefined ;
28892908 if ( openScriptInfos ) {
2890- openScriptInfos . forEach ( info => this . assignProjectToOpenedScriptInfo ( info ) ) ;
2909+ defaultConfigProjects = mapDefined ( openScriptInfos , info => this . assignProjectToOpenedScriptInfo ( info ) . defaultConfigProject ) ;
28912910 }
28922911
28932912 // While closing files there could be open files that needed assigning new inferred projects, do it now
@@ -2896,7 +2915,7 @@ namespace ts.server {
28962915 }
28972916
28982917 // Cleanup projects
2899- this . cleanupAfterOpeningFile ( ) ;
2918+ this . cleanupAfterOpeningFile ( defaultConfigProjects ) ;
29002919
29012920 // Telemetry
29022921 forEach ( openScriptInfos , info => this . telemetryOnOpenFile ( info ) ) ;
0 commit comments