@@ -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 ;
@@ -2634,10 +2638,11 @@ namespace ts.server {
26342638 return info ;
26352639 }
26362640
2637- private assignProjectToOpenedScriptInfo ( info : ScriptInfo ) : OpenConfiguredProjectResult {
2641+ private assignProjectToOpenedScriptInfo ( info : ScriptInfo ) : AssignProjectResult {
26382642 let configFileName : NormalizedPath | undefined ;
26392643 let configFileErrors : ReadonlyArray < Diagnostic > | undefined ;
26402644 let project : ConfiguredProject | ExternalProject | undefined = this . findExternalProjectContainingOpenScriptInfo ( info ) ;
2645+ let defaultConfigProject : ConfiguredProject | undefined ;
26412646 if ( ! project && ! this . syntaxOnly ) { // Checking syntaxOnly is an optimization
26422647 configFileName = this . getConfigFileNameForFile ( info ) ;
26432648 if ( configFileName ) {
@@ -2658,6 +2663,7 @@ namespace ts.server {
26582663 // Ensure project is ready to check if it contains opened script info
26592664 updateProjectIfDirty ( project ) ;
26602665 }
2666+ defaultConfigProject = project ;
26612667 }
26622668 }
26632669
@@ -2677,13 +2683,13 @@ namespace ts.server {
26772683 this . assignOrphanScriptInfoToInferredProject ( info , this . openFiles . get ( info . path ) ) ;
26782684 }
26792685 Debug . assert ( ! info . isOrphan ( ) ) ;
2680- return { configFileName, configFileErrors } ;
2686+ return { configFileName, configFileErrors, defaultConfigProject } ;
26812687 }
26822688
2683- private cleanupAfterOpeningFile ( ) {
2689+ private cleanupAfterOpeningFile ( toRetainConfigProjects : ConfiguredProject [ ] | ConfiguredProject | undefined ) {
26842690 // This was postponed from closeOpenFile to after opening next file,
26852691 // so that we can reuse the project if we need to right away
2686- this . removeOrphanConfiguredProjects ( ) ;
2692+ this . removeOrphanConfiguredProjects ( toRetainConfigProjects ) ;
26872693
26882694 // Remove orphan inferred projects now that we have reused projects
26892695 // We need to create a duplicate because we cant guarantee order after removal
@@ -2704,22 +2710,30 @@ namespace ts.server {
27042710
27052711 openClientFileWithNormalizedPath ( fileName : NormalizedPath , fileContent ?: string , scriptKind ?: ScriptKind , hasMixedContent ?: boolean , projectRootPath ?: NormalizedPath ) : OpenConfiguredProjectResult {
27062712 const info = this . getOrCreateOpenScriptInfo ( fileName , fileContent , scriptKind , hasMixedContent , projectRootPath ) ;
2707- const result = this . assignProjectToOpenedScriptInfo ( info ) ;
2708- this . cleanupAfterOpeningFile ( ) ;
2713+ const { defaultConfigProject , ... result } = this . assignProjectToOpenedScriptInfo ( info ) ;
2714+ this . cleanupAfterOpeningFile ( defaultConfigProject ) ;
27092715 this . telemetryOnOpenFile ( info ) ;
27102716 return result ;
27112717 }
27122718
2713- private removeOrphanConfiguredProjects ( ) {
2719+ private removeOrphanConfiguredProjects ( toRetainConfiguredProjects : ConfiguredProject [ ] | ConfiguredProject | undefined ) {
27142720 const toRemoveConfiguredProjects = cloneMap ( this . configuredProjects ) ;
2721+ if ( toRetainConfiguredProjects ) {
2722+ if ( isArray ( toRetainConfiguredProjects ) ) {
2723+ toRetainConfiguredProjects . forEach ( retainConfiguredProject ) ;
2724+ }
2725+ else {
2726+ retainConfiguredProject ( toRetainConfiguredProjects ) ;
2727+ }
2728+ }
27152729
27162730 // Do not remove configured projects that are used as original projects of other
27172731 this . inferredProjects . forEach ( markOriginalProjectsAsUsed ) ;
27182732 this . externalProjects . forEach ( markOriginalProjectsAsUsed ) ;
27192733 this . configuredProjects . forEach ( project => {
27202734 // 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
27212735 if ( project . hasOpenRef ( ) ) {
2722- toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2736+ retainConfiguredProject ( project ) ;
27232737 markOriginalProjectsAsUsed ( project ) ;
27242738 }
27252739 else {
@@ -2728,7 +2742,7 @@ namespace ts.server {
27282742 if ( ref ) {
27292743 const refProject = this . configuredProjects . get ( ref . sourceFile . path ) ;
27302744 if ( refProject && refProject . hasOpenRef ( ) ) {
2731- toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2745+ retainConfiguredProject ( project ) ;
27322746 }
27332747 }
27342748 } ) ;
@@ -2743,6 +2757,10 @@ namespace ts.server {
27432757 project . originalConfiguredProjects . forEach ( ( _value , configuredProjectPath ) => toRemoveConfiguredProjects . delete ( configuredProjectPath ) ) ;
27442758 }
27452759 }
2760+
2761+ function retainConfiguredProject ( project : ConfiguredProject ) {
2762+ toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2763+ }
27462764 }
27472765
27482766 private removeOrphanScriptInfos ( ) {
@@ -2885,8 +2903,9 @@ namespace ts.server {
28852903 }
28862904
28872905 // All the script infos now exist, so ok to go update projects for open files
2906+ let defaultConfigProjects : ConfiguredProject [ ] | undefined ;
28882907 if ( openScriptInfos ) {
2889- openScriptInfos . forEach ( info => this . assignProjectToOpenedScriptInfo ( info ) ) ;
2908+ defaultConfigProjects = mapDefined ( openScriptInfos , info => this . assignProjectToOpenedScriptInfo ( info ) . defaultConfigProject ) ;
28902909 }
28912910
28922911 // While closing files there could be open files that needed assigning new inferred projects, do it now
@@ -2895,7 +2914,7 @@ namespace ts.server {
28952914 }
28962915
28972916 // Cleanup projects
2898- this . cleanupAfterOpeningFile ( ) ;
2917+ this . cleanupAfterOpeningFile ( defaultConfigProjects ) ;
28992918
29002919 // Telemetry
29012920 forEach ( openScriptInfos , info => this . telemetryOnOpenFile ( info ) ) ;
0 commit comments