@@ -59,12 +59,15 @@ namespace ts {
5959 watcher : FileWatcher ;
6060 /** ref count keeping this directory watch alive */
6161 refCount : number ;
62+ /** map of refcount for the subDirectory */
63+ subDirectoryMap ?: Map < number > ;
6264 }
6365
6466 interface DirectoryOfFailedLookupWatch {
6567 dir : string ;
6668 dirPath : Path ;
6769 ignore ?: true ;
70+ subDirectory ?: Path ;
6871 }
6972
7073 export const maxNumberOfFilesToIterateForInvalidation = 256 ;
@@ -393,18 +396,20 @@ namespace ts {
393396 }
394397
395398 // Use some ancestor of the root directory
399+ let subDirectory : Path | undefined ;
396400 if ( rootPath !== undefined ) {
397401 while ( ! isInDirectoryPath ( dirPath , rootPath ) ) {
398402 const parentPath = getDirectoryPath ( dirPath ) ;
399403 if ( parentPath === dirPath ) {
400404 break ;
401405 }
406+ subDirectory = dirPath . slice ( parentPath . length + directorySeparator . length ) as Path ;
402407 dirPath = parentPath ;
403408 dir = getDirectoryPath ( dir ) ;
404409 }
405410 }
406411
407- return filterFSRootDirectoriesToWatch ( { dir, dirPath } , dirPath ) ;
412+ return filterFSRootDirectoriesToWatch ( { dir, dirPath, subDirectory } , dirPath ) ;
408413 }
409414
410415 function isPathWithDefaultFailedLookupExtension ( path : Path ) {
@@ -427,7 +432,7 @@ namespace ts {
427432 let setAtRoot = false ;
428433 for ( const failedLookupLocation of failedLookupLocations ) {
429434 const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
430- const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
435+ const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
431436 if ( ! ignore ) {
432437 // If the failed lookup location path is not one of the supported extensions,
433438 // store it in the custom path
@@ -439,7 +444,7 @@ namespace ts {
439444 setAtRoot = true ;
440445 }
441446 else {
442- setDirectoryWatcher ( dir , dirPath ) ;
447+ setDirectoryWatcher ( dir , dirPath , subDirectory ) ;
443448 }
444449 }
445450 }
@@ -449,13 +454,20 @@ namespace ts {
449454 }
450455 }
451456
452- function setDirectoryWatcher ( dir : string , dirPath : Path ) {
453- const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
457+ function setDirectoryWatcher ( dir : string , dirPath : Path , subDirectory ?: Path ) {
458+ let dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
454459 if ( dirWatcher ) {
455460 dirWatcher . refCount ++ ;
456461 }
457462 else {
458- directoryWatchesOfFailedLookups . set ( dirPath , { watcher : createDirectoryWatcher ( dir , dirPath ) , refCount : 1 } ) ;
463+ dirWatcher = { watcher : createDirectoryWatcher ( dir , dirPath ) , refCount : 1 } ;
464+ directoryWatchesOfFailedLookups . set ( dirPath , dirWatcher ) ;
465+ }
466+
467+ if ( subDirectory ) {
468+ const subDirectoryMap = dirWatcher . subDirectoryMap || ( dirWatcher . subDirectoryMap = createMap ( ) ) ;
469+ const existing = subDirectoryMap . get ( subDirectory ) || 0 ;
470+ subDirectoryMap . set ( subDirectory , existing + 1 ) ;
459471 }
460472 }
461473
@@ -473,7 +485,7 @@ namespace ts {
473485 let removeAtRoot = false ;
474486 for ( const failedLookupLocation of failedLookupLocations ) {
475487 const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
476- const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
488+ const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
477489 if ( ! ignore ) {
478490 const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) ;
479491 if ( refCount ) {
@@ -490,7 +502,7 @@ namespace ts {
490502 removeAtRoot = true ;
491503 }
492504 else {
493- removeDirectoryWatcher ( dirPath ) ;
505+ removeDirectoryWatcher ( dirPath , subDirectory ) ;
494506 }
495507 }
496508 }
@@ -499,12 +511,30 @@ namespace ts {
499511 }
500512 }
501513
502- function removeDirectoryWatcher ( dirPath : string ) {
514+ function removeDirectoryWatcher ( dirPath : string , subDirectory ?: Path ) {
503515 const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
516+ if ( subDirectory ) {
517+ const existing = dirWatcher . subDirectoryMap . get ( subDirectory ) ;
518+ if ( existing === 1 ) {
519+ dirWatcher . subDirectoryMap . delete ( subDirectory ) ;
520+ }
521+ else {
522+ dirWatcher . subDirectoryMap . set ( subDirectory , existing - 1 ) ;
523+ }
524+ }
504525 // Do not close the watcher yet since it might be needed by other failed lookup locations.
505526 dirWatcher . refCount -- ;
506527 }
507528
529+ function inWatchedSubdirectory ( dirPath : Path , fileOrDirectoryPath : Path ) {
530+ const dirWatcher = directoryWatchesOfFailedLookups . get ( dirPath ) ;
531+ if ( ! dirWatcher || ! dirWatcher . subDirectoryMap ) return false ;
532+ return forEachKey ( dirWatcher . subDirectoryMap , subDirectory => {
533+ const fullSubDirectory = `${ dirPath } /${ subDirectory } ` as Path ;
534+ return fullSubDirectory === fileOrDirectoryPath || isInDirectoryPath ( fullSubDirectory , fileOrDirectoryPath ) ;
535+ } ) ;
536+ }
537+
508538 function createDirectoryWatcher ( directory : string , dirPath : Path ) {
509539 return resolutionHost . watchDirectoryOfFailedLookupLocation ( directory , fileOrDirectory => {
510540 const fileOrDirectoryPath = resolutionHost . toPath ( fileOrDirectory ) ;
@@ -516,7 +546,7 @@ namespace ts {
516546 // If the files are added to project root or node_modules directory, always run through the invalidation process
517547 // Otherwise run through invalidation only if adding to the immediate directory
518548 if ( ! allFilesHaveInvalidatedResolution &&
519- dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrDirectoryPath ) === dirPath ) {
549+ ( dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrDirectoryPath ) === dirPath || inWatchedSubdirectory ( dirPath , fileOrDirectoryPath ) ) ) {
520550 if ( invalidateResolutionOfFailedLookupLocation ( fileOrDirectoryPath , dirPath === fileOrDirectoryPath ) ) {
521551 resolutionHost . onInvalidatedResolution ( ) ;
522552 }
0 commit comments