@@ -153,9 +153,9 @@ namespace ts {
153
153
const resolvedFileToResolution = createMultiMap < ResolutionWithFailedLookupLocations > ( ) ;
154
154
155
155
let hasChangedAutomaticTypeDirectiveNames = false ;
156
- const failedLookupChecks : Path [ ] = [ ] ;
157
- const startsWithPathChecks : Path [ ] = [ ] ;
158
- const isInDirectoryChecks : Path [ ] = [ ] ;
156
+ let failedLookupChecks : Path [ ] | undefined ;
157
+ let startsWithPathChecks : Set < Path > | undefined ;
158
+ let isInDirectoryChecks : Path [ ] | undefined ;
159
159
160
160
const getCurrentDirectory = memoize ( ( ) => resolutionHost . getCurrentDirectory ! ( ) ) ; // TODO: GH#18217
161
161
const cachedDirectoryStructureHost = resolutionHost . getCachedDirectoryStructureHost ( ) ;
@@ -248,9 +248,9 @@ namespace ts {
248
248
resolvedTypeReferenceDirectives . clear ( ) ;
249
249
resolvedFileToResolution . clear ( ) ;
250
250
resolutionsWithFailedLookups . length = 0 ;
251
- failedLookupChecks . length = 0 ;
252
- startsWithPathChecks . length = 0 ;
253
- isInDirectoryChecks . length = 0 ;
251
+ failedLookupChecks = undefined ;
252
+ startsWithPathChecks = undefined ;
253
+ isInDirectoryChecks = undefined ;
254
254
// perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
255
255
// (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
256
256
clearPerDirectoryResolutions ( ) ;
@@ -766,7 +766,7 @@ namespace ts {
766
766
if ( isCreatingWatchedDirectory ) {
767
767
// Watching directory is created
768
768
// Invalidate any resolution has failed lookup in this directory
769
- isInDirectoryChecks . push ( fileOrDirectoryPath ) ;
769
+ ( isInDirectoryChecks ||= [ ] ) . push ( fileOrDirectoryPath ) ;
770
770
}
771
771
else {
772
772
// If something to do with folder/file starting with "." in node_modules folder, skip it
@@ -785,8 +785,8 @@ namespace ts {
785
785
if ( isNodeModulesAtTypesDirectory ( fileOrDirectoryPath ) || isNodeModulesDirectory ( fileOrDirectoryPath ) ||
786
786
isNodeModulesAtTypesDirectory ( dirOfFileOrDirectory ) || isNodeModulesDirectory ( dirOfFileOrDirectory ) ) {
787
787
// Invalidate any resolution from this directory
788
- failedLookupChecks . push ( fileOrDirectoryPath ) ;
789
- startsWithPathChecks . push ( fileOrDirectoryPath ) ;
788
+ ( failedLookupChecks ||= [ ] ) . push ( fileOrDirectoryPath ) ;
789
+ ( startsWithPathChecks ||= new Set ( ) ) . add ( fileOrDirectoryPath ) ;
790
790
}
791
791
else {
792
792
if ( ! isPathWithDefaultFailedLookupExtension ( fileOrDirectoryPath ) && ! customFailedLookupPaths . has ( fileOrDirectoryPath ) ) {
@@ -797,30 +797,36 @@ namespace ts {
797
797
return false ;
798
798
}
799
799
// Resolution need to be invalidated if failed lookup location is same as the file or directory getting created
800
- failedLookupChecks . push ( fileOrDirectoryPath ) ;
800
+ ( failedLookupChecks ||= [ ] ) . push ( fileOrDirectoryPath ) ;
801
+
802
+ // If the invalidated file is from a node_modules package, invalidate everything else
803
+ // in the package since we might not get notifications for other files in the package.
804
+ // This hardens our logic against unreliable file watchers.
805
+ const packagePath = parseNodeModuleFromPath ( fileOrDirectoryPath ) ;
806
+ if ( packagePath ) ( startsWithPathChecks ||= new Set ( ) ) . add ( packagePath as Path ) ;
801
807
}
802
808
}
803
809
resolutionHost . scheduleInvalidateResolutionsOfFailedLookupLocations ( ) ;
804
810
}
805
811
806
812
function invalidateResolutionsOfFailedLookupLocations ( ) {
807
- if ( ! failedLookupChecks . length && ! startsWithPathChecks . length && ! isInDirectoryChecks . length ) {
813
+ if ( ! failedLookupChecks && ! startsWithPathChecks && ! isInDirectoryChecks ) {
808
814
return false ;
809
815
}
810
816
811
817
const invalidated = invalidateResolutions ( resolutionsWithFailedLookups , canInvalidateFailedLookupResolution ) ;
812
- failedLookupChecks . length = 0 ;
813
- startsWithPathChecks . length = 0 ;
814
- isInDirectoryChecks . length = 0 ;
818
+ failedLookupChecks = undefined ;
819
+ startsWithPathChecks = undefined ;
820
+ isInDirectoryChecks = undefined ;
815
821
return invalidated ;
816
822
}
817
823
818
824
function canInvalidateFailedLookupResolution ( resolution : ResolutionWithFailedLookupLocations ) {
819
825
return resolution . failedLookupLocations . some ( location => {
820
826
const locationPath = resolutionHost . toPath ( location ) ;
821
827
return contains ( failedLookupChecks , locationPath ) ||
822
- startsWithPathChecks . some ( fileOrDirectoryPath => startsWith ( locationPath , fileOrDirectoryPath ) ) ||
823
- isInDirectoryChecks . some ( fileOrDirectoryPath => isInDirectoryPath ( fileOrDirectoryPath , locationPath ) ) ;
828
+ firstDefinedIterator ( startsWithPathChecks ?. keys ( ) || emptyIterator , fileOrDirectoryPath => startsWith ( locationPath , fileOrDirectoryPath ) ? true : undefined ) ||
829
+ isInDirectoryChecks ? .some ( fileOrDirectoryPath => isInDirectoryPath ( fileOrDirectoryPath , locationPath ) ) ;
824
830
} ) ;
825
831
}
826
832
0 commit comments