@@ -59,12 +59,15 @@ namespace ts {
59
59
watcher : FileWatcher ;
60
60
/** ref count keeping this directory watch alive */
61
61
refCount : number ;
62
+ /** map of refcount for the subDirectory */
63
+ subDirectoryMap ?: Map < number > ;
62
64
}
63
65
64
66
interface DirectoryOfFailedLookupWatch {
65
67
dir : string ;
66
68
dirPath : Path ;
67
69
ignore ?: true ;
70
+ subDirectory ?: Path ;
68
71
}
69
72
70
73
export const maxNumberOfFilesToIterateForInvalidation = 256 ;
@@ -393,18 +396,20 @@ namespace ts {
393
396
}
394
397
395
398
// Use some ancestor of the root directory
399
+ let subDirectory : Path | undefined ;
396
400
if ( rootPath !== undefined ) {
397
401
while ( ! isInDirectoryPath ( dirPath , rootPath ) ) {
398
402
const parentPath = getDirectoryPath ( dirPath ) ;
399
403
if ( parentPath === dirPath ) {
400
404
break ;
401
405
}
406
+ subDirectory = dirPath . slice ( parentPath . length + directorySeparator . length ) as Path ;
402
407
dirPath = parentPath ;
403
408
dir = getDirectoryPath ( dir ) ;
404
409
}
405
410
}
406
411
407
- return filterFSRootDirectoriesToWatch ( { dir, dirPath } , dirPath ) ;
412
+ return filterFSRootDirectoriesToWatch ( { dir, dirPath, subDirectory } , dirPath ) ;
408
413
}
409
414
410
415
function isPathWithDefaultFailedLookupExtension ( path : Path ) {
@@ -427,7 +432,7 @@ namespace ts {
427
432
let setAtRoot = false ;
428
433
for ( const failedLookupLocation of failedLookupLocations ) {
429
434
const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
430
- const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
435
+ const { dir, dirPath, ignore , subDirectory } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
431
436
if ( ! ignore ) {
432
437
// If the failed lookup location path is not one of the supported extensions,
433
438
// store it in the custom path
@@ -439,7 +444,7 @@ namespace ts {
439
444
setAtRoot = true ;
440
445
}
441
446
else {
442
- setDirectoryWatcher ( dir , dirPath ) ;
447
+ setDirectoryWatcher ( dir , dirPath , subDirectory ) ;
443
448
}
444
449
}
445
450
}
@@ -449,13 +454,20 @@ namespace ts {
449
454
}
450
455
}
451
456
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 ) ;
454
459
if ( dirWatcher ) {
455
460
dirWatcher . refCount ++ ;
456
461
}
457
462
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 ) ;
459
471
}
460
472
}
461
473
@@ -473,7 +485,7 @@ namespace ts {
473
485
let removeAtRoot = false ;
474
486
for ( const failedLookupLocation of failedLookupLocations ) {
475
487
const failedLookupLocationPath = resolutionHost . toPath ( failedLookupLocation ) ;
476
- const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
488
+ const { dirPath, ignore, subDirectory } = getDirectoryToWatchFailedLookupLocation ( failedLookupLocation , failedLookupLocationPath ) ;
477
489
if ( ! ignore ) {
478
490
const refCount = customFailedLookupPaths . get ( failedLookupLocationPath ) ;
479
491
if ( refCount ) {
@@ -490,7 +502,7 @@ namespace ts {
490
502
removeAtRoot = true ;
491
503
}
492
504
else {
493
- removeDirectoryWatcher ( dirPath ) ;
505
+ removeDirectoryWatcher ( dirPath , subDirectory ) ;
494
506
}
495
507
}
496
508
}
@@ -499,12 +511,30 @@ namespace ts {
499
511
}
500
512
}
501
513
502
- function removeDirectoryWatcher ( dirPath : string ) {
514
+ function removeDirectoryWatcher ( dirPath : string , subDirectory ?: Path ) {
503
515
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
+ }
504
525
// Do not close the watcher yet since it might be needed by other failed lookup locations.
505
526
dirWatcher . refCount -- ;
506
527
}
507
528
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
+
508
538
function createDirectoryWatcher ( directory : string , dirPath : Path ) {
509
539
return resolutionHost . watchDirectoryOfFailedLookupLocation ( directory , fileOrDirectory => {
510
540
const fileOrDirectoryPath = resolutionHost . toPath ( fileOrDirectory ) ;
@@ -516,7 +546,7 @@ namespace ts {
516
546
// If the files are added to project root or node_modules directory, always run through the invalidation process
517
547
// Otherwise run through invalidation only if adding to the immediate directory
518
548
if ( ! allFilesHaveInvalidatedResolution &&
519
- dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrDirectoryPath ) === dirPath ) {
549
+ ( dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrDirectoryPath ) === dirPath || inWatchedSubdirectory ( dirPath , fileOrDirectoryPath ) ) ) {
520
550
if ( invalidateResolutionOfFailedLookupLocation ( fileOrDirectoryPath , dirPath === fileOrDirectoryPath ) ) {
521
551
resolutionHost . onInvalidatedResolution ( ) ;
522
552
}
0 commit comments