@@ -707,7 +707,7 @@ namespace ts.server {
707
707
708
708
/* @internal */
709
709
private forEachProject ( cb : ( project : Project ) => void ) {
710
- for ( const p of this . inferredProjects ) cb ( p ) ;
710
+ this . inferredProjects . forEach ( cb ) ;
711
711
this . configuredProjects . forEach ( cb ) ;
712
712
this . externalProjects . forEach ( cb ) ;
713
713
}
@@ -2110,19 +2110,34 @@ namespace ts.server {
2110
2110
if ( ! originalLocation ) return undefined ;
2111
2111
2112
2112
const { fileName } = originalLocation ;
2113
- const originalScriptInfo = this . getScriptInfo ( fileName ) ;
2114
- if ( originalScriptInfo && originalScriptInfo . containingProjects . length ) {
2115
- return originalLocation ;
2116
- }
2113
+ if ( ! this . getScriptInfo ( fileName ) && ! this . host . fileExists ( fileName ) ) return undefined ;
2117
2114
2118
- const info : OriginalFileInfo = { fileName : toNormalizedPath ( fileName ) , path : this . toPath ( fileName ) } ;
2119
- const configFileName = this . getConfigFileNameForFile ( info ) ;
2115
+ const originalFileInfo : OriginalFileInfo = { fileName : toNormalizedPath ( fileName ) , path : this . toPath ( fileName ) } ;
2116
+ const configFileName = this . getConfigFileNameForFile ( originalFileInfo ) ;
2120
2117
if ( ! configFileName ) return undefined ;
2121
2118
2122
2119
const configuredProject = this . findConfiguredProjectByProjectName ( configFileName ) || this . createConfiguredProject ( configFileName ) ;
2123
2120
updateProjectIfDirty ( configuredProject ) ;
2121
+ // Keep this configured project as referenced from project
2122
+ addOriginalConfiguredProject ( configuredProject ) ;
2123
+
2124
+ const originalScriptInfo = this . getScriptInfo ( fileName ) ;
2125
+ if ( ! originalScriptInfo || ! originalScriptInfo . containingProjects . length ) return undefined ;
2124
2126
2125
- return configuredProject . containsFile ( info . fileName ) ? originalLocation : undefined ;
2127
+ // Add configured projects as referenced
2128
+ originalScriptInfo . containingProjects . forEach ( project => {
2129
+ if ( project . projectKind === ProjectKind . Configured ) {
2130
+ addOriginalConfiguredProject ( project as ConfiguredProject ) ;
2131
+ }
2132
+ } ) ;
2133
+ return originalLocation ;
2134
+
2135
+ function addOriginalConfiguredProject ( originalProject : ConfiguredProject ) {
2136
+ if ( ! project . originalConfiguredProjects ) {
2137
+ project . originalConfiguredProjects = createMap < true > ( ) ;
2138
+ }
2139
+ project . originalConfiguredProjects . set ( originalProject . canonicalConfigFilePath , true ) ;
2140
+ }
2126
2141
}
2127
2142
2128
2143
/** @internal */
@@ -2185,14 +2200,9 @@ namespace ts.server {
2185
2200
}
2186
2201
Debug . assert ( ! info . isOrphan ( ) ) ;
2187
2202
2188
- // Remove the configured projects that have zero references from open files.
2189
2203
// This was postponed from closeOpenFile to after opening next file,
2190
2204
// so that we can reuse the project if we need to right away
2191
- this . configuredProjects . forEach ( project => {
2192
- if ( ! project . hasOpenRef ( ) ) {
2193
- this . removeProject ( project ) ;
2194
- }
2195
- } ) ;
2205
+ this . removeOrphanConfiguredProjects ( ) ;
2196
2206
2197
2207
// Remove orphan inferred projects now that we have reused projects
2198
2208
// We need to create a duplicate because we cant guarantee order after removal
@@ -2220,6 +2230,30 @@ namespace ts.server {
2220
2230
return { configFileName, configFileErrors } ;
2221
2231
}
2222
2232
2233
+ private removeOrphanConfiguredProjects ( ) {
2234
+ const toRemoveConfiguredProjects = cloneMap ( this . configuredProjects ) ;
2235
+
2236
+ // Do not remove configured projects that are used as original projects of other
2237
+ this . inferredProjects . forEach ( markOriginalProjectsAsUsed ) ;
2238
+ this . externalProjects . forEach ( markOriginalProjectsAsUsed ) ;
2239
+ this . configuredProjects . forEach ( project => {
2240
+ // 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
2241
+ if ( project . hasOpenRef ( ) ) {
2242
+ toRemoveConfiguredProjects . delete ( project . canonicalConfigFilePath ) ;
2243
+ markOriginalProjectsAsUsed ( project ) ;
2244
+ }
2245
+ } ) ;
2246
+
2247
+ // Remove all the non marked projects
2248
+ toRemoveConfiguredProjects . forEach ( project => this . removeProject ( project ) ) ;
2249
+
2250
+ function markOriginalProjectsAsUsed ( project : Project ) {
2251
+ if ( ! project . isOrphan ( ) && project . originalConfiguredProjects ) {
2252
+ project . originalConfiguredProjects . forEach ( ( _value , configuredProjectPath ) => toRemoveConfiguredProjects . delete ( configuredProjectPath ) ) ;
2253
+ }
2254
+ }
2255
+ }
2256
+
2223
2257
private telemetryOnOpenFile ( scriptInfo : ScriptInfo ) : void {
2224
2258
if ( this . syntaxOnly || ! this . eventHandler || ! scriptInfo . isJavaScript ( ) || ! addToSeen ( this . allJsFilesForOpenFileTelemetry , scriptInfo . path ) ) {
2225
2259
return ;
0 commit comments