@@ -50,8 +50,6 @@ namespace ts {
50
50
writeLog ( s : string ) : void ;
51
51
}
52
52
53
- const MAX_DIRPATHS_TO_RECURSE = 5 ;
54
-
55
53
export function createResolutionCache ( resolutionHost : ResolutionCacheHost ) : ResolutionCache {
56
54
let filesWithChangedSetOfUnresolvedImports : Path [ ] | undefined ;
57
55
let filesWithInvalidatedResolutions : Map < true > | undefined ;
@@ -264,7 +262,6 @@ namespace ts {
264
262
}
265
263
266
264
function resolveTypeReferenceDirectives ( typeDirectiveNames : string [ ] , containingFile : string ) : ResolvedTypeReferenceDirective [ ] {
267
- resolutionHost . writeLog ( `resolveTypeReferenceDirectives: ${ typeDirectiveNames } in ${ containingFile } ` ) ;
268
265
return resolveNamesWithLocalCache (
269
266
typeDirectiveNames , containingFile ,
270
267
resolvedTypeReferenceDirectives , perDirectoryResolvedTypeReferenceDirectives ,
@@ -274,7 +271,6 @@ namespace ts {
274
271
}
275
272
276
273
function resolveModuleNames ( moduleNames : string [ ] , containingFile : string , logChanges : boolean ) : ResolvedModuleFull [ ] {
277
- resolutionHost . writeLog ( `resolveModuleNames: ${ moduleNames } in ${ containingFile } ` ) ;
278
274
return resolveNamesWithLocalCache (
279
275
moduleNames , containingFile ,
280
276
resolvedModuleNames , perDirectoryResolvedModuleNames ,
@@ -284,48 +280,64 @@ namespace ts {
284
280
}
285
281
286
282
function watchFailedLookupLocation ( failedLookupLocation : string , failedLookupLocationPath : Path ) {
287
- const cachedDir = failedLookupLocationToDirPath . get ( failedLookupLocationPath ) ;
288
- if ( cachedDir ) {
289
- watchFailedLookupLocationInDirectory ( cachedDir , failedLookupLocationPath , /*dir*/ undefined ) ;
283
+ const failedLocationDirPath = getDirectoryPath ( failedLookupLocationPath ) ;
284
+ const cachedDirPath = failedLookupLocationToDirPath . get ( failedLocationDirPath ) ;
285
+ if ( cachedDirPath ) {
286
+ watchFailedLookupLocationInDirectory ( cachedDirPath , failedLookupLocationPath , /*dir*/ undefined ) ;
290
287
return ;
291
288
}
292
289
293
290
if ( isInDirectoryPath ( rootPath , failedLookupLocationPath ) ) {
294
291
// Watch in directory of rootPath
292
+ failedLookupLocationToDirPath . set ( failedLocationDirPath , rootPath ) ;
295
293
watchFailedLookupLocationInDirectory ( rootPath , failedLookupLocationPath , rootDir ) ;
296
294
return ;
297
295
}
298
296
299
- let dirPath = getDirectoryPath ( failedLookupLocationPath ) ;
300
- let dir = getDirectoryPath ( getNormalizedAbsolutePath ( failedLookupLocation , getCurrentDirectory ( ) ) ) ;
301
- for ( let i = 0 ; i < MAX_DIRPATHS_TO_RECURSE ; i ++ ) {
302
- const parentPath = getDirectoryPath ( dirPath ) ;
303
- if ( directoryWatchesOfFailedLookups . has ( dirPath ) || parentPath === dirPath ) {
304
- watchFailedLookupLocationInDirectory ( dirPath , failedLookupLocationPath , dir ) ;
305
- return ;
306
- }
307
- dirPath = parentPath ;
308
- dir = getDirectoryPath ( dir ) ;
309
- }
297
+ const { dir, dirPath } = getDirectoryToWatchWhenNotInRootPath (
298
+ getDirectoryPath ( getNormalizedAbsolutePath ( failedLookupLocation , getCurrentDirectory ( ) ) ) ,
299
+ getDirectoryPath ( failedLookupLocationPath )
300
+ ) ;
301
+ failedLookupLocationToDirPath . set ( failedLocationDirPath , dirPath ) ;
302
+ watchFailedLookupLocationInDirectory ( dirPath , failedLookupLocationPath , dir ) ;
303
+ }
310
304
311
- // Verify there are no watches in parent directory
312
- const ancestorDirPath = getAncestorDirectoryWithWatches ( dirPath ) ;
313
- // We wont need directory if we are using ancestor since its already cached
314
- watchFailedLookupLocationInDirectory ( ancestorDirPath || dirPath , failedLookupLocationPath , dir ) ;
305
+ function isNodeModulesDirectory ( dirPath : Path ) {
306
+ const nodemodules = "/node_modules" ;
307
+ return endsWith ( dirPath , nodemodules ) ;
315
308
}
316
309
317
- function getAncestorDirectoryWithWatches ( dirPath : Path ) {
318
- for ( let parentDirPath = getDirectoryPath ( dirPath ) ; parentDirPath !== dirPath ; parentDirPath = getDirectoryPath ( parentDirPath ) ) {
319
- if ( directoryWatchesOfFailedLookups . has ( parentDirPath ) ) {
320
- return parentDirPath ;
310
+ function getDirectoryToWatchWhenNotInRootPath ( dir : string , dirPath : Path ) : { dir : string , dirPath : Path } {
311
+ // If the directory is node_modules use it to watch
312
+ if ( isNodeModulesDirectory ( dirPath ) ) {
313
+ return { dir, dirPath } ;
314
+ }
315
+
316
+ // If directory path contains node module, get the node_modules directory for watching
317
+ if ( dirPath . indexOf ( "/node_modules/" ) !== - 1 ) {
318
+ while ( ! isNodeModulesDirectory ( dirPath ) ) {
319
+ dir = getDirectoryPath ( dir ) ;
320
+ dirPath = getDirectoryPath ( dirPath ) ;
321
+ }
322
+ return { dir, dirPath } ;
323
+ }
324
+
325
+ // Use some ancestor of the root directory
326
+ if ( rootPath !== undefined ) {
327
+ while ( ! isInDirectoryPath ( dirPath , rootPath ) ) {
328
+ const parentPath = getDirectoryPath ( dirPath ) ;
329
+ if ( parentPath === dirPath ) {
330
+ break ;
331
+ }
332
+ dirPath = parentPath ;
333
+ dir = getDirectoryPath ( dir ) ;
321
334
}
322
- dirPath = parentDirPath ;
323
335
}
324
- return undefined ;
336
+
337
+ return { dir, dirPath } ;
325
338
}
326
339
327
340
function watchFailedLookupLocationInDirectory ( dirPath : Path , failedLookupLocationPath : Path , dir : string | undefined ) {
328
- failedLookupLocationToDirPath . set ( failedLookupLocationPath , dirPath ) ;
329
341
const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
330
342
if ( watches ) {
331
343
const existingCount = watches . mapLocations . get ( failedLookupLocationPath ) || 0 ;
@@ -350,31 +362,37 @@ namespace ts {
350
362
resolutionHost . getCachedPartialSystem ( ) . addOrDeleteFileOrFolder ( fileOrFolder , fileOrFolderPath ) ;
351
363
}
352
364
353
- // If the location results in update to failed lookup, schedule program update
354
- if ( dirPath === fileOrFolderPath ) {
355
- onAddOrRemoveDirectoryOfFailedLookup ( dirPath ) ;
356
- resolutionHost . onInvalidatedResolution ( ) ;
357
- }
358
- else if ( onFileAddOrRemoveInDirectoryOfFailedLookup ( dirPath , fileOrFolderPath ) ) {
359
- resolutionHost . onInvalidatedResolution ( ) ;
365
+ // If the files are added to project root or node_modules directory, always run through the invalidation process
366
+ // Otherwise run through invalidation only if adding to the immediate directory
367
+ if ( dirPath === rootPath || isNodeModulesDirectory ( dirPath ) || getDirectoryPath ( fileOrFolderPath ) === dirPath ) {
368
+ // If the location results in update to failed lookup, schedule program update
369
+ if ( dirPath === fileOrFolderPath ) {
370
+ if ( onAddOrRemoveDirectoryOfFailedLookup ( dirPath ) ) {
371
+ resolutionHost . onInvalidatedResolution ( ) ;
372
+ }
373
+ }
374
+ else if ( onFileAddOrRemoveInDirectoryOfFailedLookup ( dirPath , fileOrFolderPath ) ) {
375
+ resolutionHost . onInvalidatedResolution ( ) ;
376
+ }
360
377
}
361
378
} , WatchDirectoryFlags . Recursive ) ;
362
379
}
363
380
364
381
function closeFailedLookupLocationWatcher ( _failedLookupLocation : string , failedLookupLocationPath : Path ) {
365
- const dirPath = failedLookupLocationToDirPath . get ( failedLookupLocationPath ) ;
382
+ const failedLookupDirectory = getDirectoryPath ( failedLookupLocationPath ) ;
383
+ const dirPath = failedLookupLocationToDirPath . get ( failedLookupDirectory ) ;
366
384
const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
367
385
const refCount = watches . mapLocations . get ( failedLookupLocationPath ) ;
368
386
if ( refCount === 1 ) {
369
387
// If this was last failed lookup location being tracked by the dir watcher,
370
388
// remove the failed lookup location path to dir Path entry
371
389
watches . mapLocations . delete ( failedLookupLocationPath ) ;
372
- failedLookupLocationToDirPath . delete ( failedLookupLocationPath ) ;
373
390
374
391
// If there are no more files that need this watcher alive, close the watcher
375
392
if ( watches . mapLocations . size === 0 ) {
376
393
watches . watcher . close ( ) ;
377
394
directoryWatchesOfFailedLookups . delete ( dirPath ) ;
395
+ failedLookupLocationToDirPath . delete ( failedLookupDirectory ) ;
378
396
}
379
397
}
380
398
else {
@@ -455,19 +473,22 @@ namespace ts {
455
473
456
474
function onFileAddOrRemoveInDirectoryOfFailedLookup ( dirPath : Path , fileOrFolder : Path ) {
457
475
const watches = directoryWatchesOfFailedLookups . get ( dirPath ) ;
458
- const isFailedLookupFile = watches . mapLocations . has ( fileOrFolder ) ;
459
- if ( isFailedLookupFile ) {
476
+ if ( watches . mapLocations . has ( fileOrFolder ) ) {
477
+ const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size ;
460
478
const isFileOrFolder : ( location : string ) => boolean = location => resolutionHost . toPath ( location ) === fileOrFolder ;
461
479
invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedModuleNames , isFileOrFolder ) ;
462
480
invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedTypeReferenceDirectives , isFileOrFolder ) ;
481
+ return filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size !== invalidatedFiles ;
463
482
}
464
- return isFailedLookupFile ;
483
+ return false ;
465
484
}
466
485
467
486
function onAddOrRemoveDirectoryOfFailedLookup ( dirPath : Path ) {
487
+ const invalidatedFiles = filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size ;
468
488
const isInDirPath : ( location : string ) => boolean = location => isInDirectoryPath ( dirPath , resolutionHost . toPath ( location ) ) ;
469
489
invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedModuleNames , isInDirPath ) ;
470
490
invalidateResolutionCacheOfChangedFailedLookupLocation ( resolvedTypeReferenceDirectives , isInDirPath ) ;
491
+ filesWithInvalidatedResolutions && filesWithInvalidatedResolutions . size !== invalidatedFiles ;
471
492
}
472
493
473
494
function closeTypeRootsWatch ( ) {
0 commit comments