@@ -641,10 +641,6 @@ namespace ts.server {
641641 errors : Diagnostic [ ] | undefined ;
642642 }
643643
644- interface SharedExtendedConfigFileWatcher extends FileWatcher {
645- projects : Set < ConfiguredProject > ;
646- }
647-
648644 export class ProjectService {
649645
650646 /*@internal */
@@ -761,7 +757,7 @@ namespace ts.server {
761757 readonly watchFactory : WatchFactory < WatchType , Project > ;
762758
763759 /*@internal */
764- private readonly sharedExtendedConfigFileWatchers = new Map < Path , SharedExtendedConfigFileWatcher > ( ) ;
760+ private readonly sharedExtendedConfigFileWatchers = new Map < Path , SharedExtendedConfigFileWatcher < NormalizedPath > > ( ) ;
765761
766762 /*@internal */
767763 readonly packageJsonCache : PackageJsonCache ;
@@ -1359,61 +1355,40 @@ namespace ts.server {
13591355 }
13601356
13611357 /*@internal */
1362- private updateSharedExtendedConfigFileMap ( project : ConfiguredProject ) {
1363- const extendedConfigPaths : readonly Path [ ] = project . getCompilerOptions ( ) . configFile ?. extendedSourceFiles
1364- ?. map ( ( file ) => this . toPath ( file ) ) ?? emptyArray ;
1365- for ( const extendedConfigPath of extendedConfigPaths ) {
1366- const watcher = this . sharedExtendedConfigFileWatchers . get ( extendedConfigPath ) ;
1367- if ( watcher ) {
1368- watcher . projects . add ( project ) ;
1369- }
1370- else {
1371- // start watching previously unseen extended config
1372- const projects = new Set < ConfiguredProject > ( [ project ] ) ;
1373- const fileWatcherCallback = ( ) => {
1374- const reason = `Change in extended config file ${ extendedConfigPath } detected` ;
1375- projects . forEach ( ( project : ConfiguredProject ) => {
1358+ updateSharedExtendedConfigFileMap ( { canonicalConfigFilePath } : ConfiguredProject , parsedCommandLine : ParsedCommandLine ) {
1359+ updateSharedExtendedConfigFileWatcher (
1360+ canonicalConfigFilePath ,
1361+ parsedCommandLine ,
1362+ this . sharedExtendedConfigFileWatchers ,
1363+ ( extendedConfigFileName , extendedConfigFilePath ) => this . watchFactory . watchFile (
1364+ extendedConfigFileName ,
1365+ ( ) => {
1366+ let ensureProjectsForOpenFiles = false ;
1367+ this . sharedExtendedConfigFileWatchers . get ( extendedConfigFilePath ) ?. projects . forEach ( canonicalPath => {
1368+ const project = this . configuredProjects . get ( canonicalPath ) ;
13761369 // Skip refresh if project is not yet loaded
1377- if ( project . isInitialLoadPending ( ) ) return ;
1370+ if ( ! project || project . isInitialLoadPending ( ) ) return ;
13781371 project . pendingReload = ConfigFileProgramReloadLevel . Full ;
1379- project . pendingReloadReason = reason ;
1372+ project . pendingReloadReason = `Change in extended config file ${ extendedConfigFileName } detected` ;
13801373 this . delayUpdateProjectGraph ( project ) ;
1374+ ensureProjectsForOpenFiles = true ;
13811375 } ) ;
1382- } ;
1383- const fileWatcher = this . watchFactory . watchFile (
1384- extendedConfigPath ,
1385- fileWatcherCallback ,
1386- PollingInterval . High ,
1387- this . hostConfiguration . watchOptions ,
1388- WatchType . ExtendedConfigFile
1389- ) ;
1390- this . sharedExtendedConfigFileWatchers . set ( extendedConfigPath , {
1391- close : ( ) => fileWatcher . close ( ) ,
1392- projects,
1393- } ) ;
1394- }
1395- }
1396- // remove project from all unrelated watchers
1397- this . sharedExtendedConfigFileWatchers . forEach ( ( watcher , extendedConfigPath ) => {
1398- if ( ! extendedConfigPaths . includes ( extendedConfigPath ) ) {
1399- watcher . projects . delete ( project ) ;
1400- if ( watcher . projects . size === 0 ) {
1401- watcher . close ( ) ;
1402- this . sharedExtendedConfigFileWatchers . delete ( extendedConfigPath ) ;
1403- }
1404- }
1405- } ) ;
1376+ if ( ensureProjectsForOpenFiles ) this . delayEnsureProjectForOpenFiles ( ) ;
1377+ } ,
1378+ PollingInterval . High ,
1379+ this . hostConfiguration . watchOptions ,
1380+ WatchType . ExtendedConfigFile
1381+ ) ,
1382+ fileName => this . toPath ( fileName ) ,
1383+ ) ;
14061384 }
14071385
14081386 /*@internal */
1409- private removeProjectFromSharedExtendedConfigFileMap ( project : ConfiguredProject ) {
1410- for ( const [ sharedConfigPath , watcher ] of arrayFrom ( this . sharedExtendedConfigFileWatchers . entries ( ) ) ) {
1411- watcher . projects . delete ( project ) ;
1412- if ( watcher . projects . size === 0 ) {
1413- watcher . close ( ) ;
1414- this . sharedExtendedConfigFileWatchers . delete ( sharedConfigPath ) ;
1415- }
1416- }
1387+ removeProjectFromSharedExtendedConfigFileMap ( project : ConfiguredProject ) {
1388+ this . sharedExtendedConfigFileWatchers . forEach ( watcher => {
1389+ watcher . projects . delete ( project . canonicalConfigFilePath ) ;
1390+ watcher . close ( ) ;
1391+ } ) ;
14171392 }
14181393
14191394 /**
@@ -1471,7 +1446,6 @@ namespace ts.server {
14711446 this . configuredProjects . delete ( ( < ConfiguredProject > project ) . canonicalConfigFilePath ) ;
14721447 this . projectToSizeMap . delete ( ( project as ConfiguredProject ) . canonicalConfigFilePath ) ;
14731448 this . setConfigFileExistenceInfoByClosedConfiguredProject ( < ConfiguredProject > project ) ;
1474- this . removeProjectFromSharedExtendedConfigFileMap ( project as ConfiguredProject ) ;
14751449 break ;
14761450 case ProjectKind . Inferred :
14771451 unorderedRemoveItem ( this . inferredProjects , < InferredProject > project ) ;
@@ -2208,7 +2182,7 @@ namespace ts.server {
22082182 project . setWatchOptions ( parsedCommandLine . watchOptions ) ;
22092183 project . enableLanguageService ( ) ;
22102184 project . watchWildcards ( new Map ( getEntries ( parsedCommandLine . wildcardDirectories ! ) ) ) ; // TODO: GH#18217
2211- this . updateSharedExtendedConfigFileMap ( project ) ;
2185+ this . updateSharedExtendedConfigFileMap ( project , parsedCommandLine ) ;
22122186 }
22132187 project . enablePluginsWithOptions ( compilerOptions , this . currentPluginConfigOverrides ) ;
22142188 const filesToAdd = parsedCommandLine . fileNames . concat ( project . getExternalFiles ( ) ) ;
0 commit comments