@@ -89,7 +89,18 @@ namespace ts.server {
8989 private plugins : PluginModule [ ] = [ ] ;
9090
9191 /*@internal */
92+ /**
93+ * This is map from files to unresolved imports in it
94+ * Maop does not contain entries for files that do not have unresolved imports
95+ * This helps in containing the set of files to invalidate
96+ */
9297 cachedUnresolvedImportsPerFile = createMap < ReadonlyArray < string > > ( ) ;
98+
99+ /**
100+ * This is the set that has entry to true if file doesnt contain any unresolved import
101+ */
102+ private filesWithNoUnresolvedImports = createMap < true > ( ) ;
103+
93104 /*@internal */
94105 lastCachedUnresolvedImportsList : SortedReadonlyArray < string > ;
95106 /*@internal */
@@ -143,7 +154,8 @@ namespace ts.server {
143154 /*@internal */
144155 hasChangedAutomaticTypeDirectiveNames = false ;
145156
146- private typingFiles : SortedReadonlyArray < string > ;
157+ /*@internal */
158+ typingFiles : SortedReadonlyArray < string > = emptyArray ;
147159
148160 private readonly cancellationToken : ThrottledCancellationToken ;
149161
@@ -554,6 +566,7 @@ namespace ts.server {
554566 this . resolutionCache . clear ( ) ;
555567 this . resolutionCache = undefined ;
556568 this . cachedUnresolvedImportsPerFile = undefined ;
569+ this . filesWithNoUnresolvedImports = undefined ;
557570 this . directoryStructureHost = undefined ;
558571
559572 // Clean up file watchers waiting for missing files
@@ -714,6 +727,7 @@ namespace ts.server {
714727 else {
715728 this . resolutionCache . invalidateResolutionOfFile ( info . path ) ;
716729 }
730+ this . filesWithNoUnresolvedImports . delete ( info . path ) ;
717731 this . cachedUnresolvedImportsPerFile . delete ( info . path ) ;
718732
719733 if ( detachFromProject ) {
@@ -735,16 +749,21 @@ namespace ts.server {
735749 }
736750
737751 /* @internal */
738- private extractUnresolvedImportsFromSourceFile ( file : SourceFile , result : Push < string > , ambientModules : string [ ] ) {
752+ private extractUnresolvedImportsFromSourceFile ( file : SourceFile , result : string [ ] | undefined , ambientModules : string [ ] ) : string [ ] | undefined {
753+ // No unresolve imports in this file
754+ if ( this . filesWithNoUnresolvedImports . has ( file . path ) ) {
755+ return result ;
756+ }
757+
739758 const cached = this . cachedUnresolvedImportsPerFile . get ( file . path ) ;
740759 if ( cached ) {
741760 // found cached result - use it and return
742761 for ( const f of cached ) {
743- result . push ( f ) ;
762+ ( result || ( result = [ ] ) ) . push ( f ) ;
744763 }
745- return ;
764+ return result ;
746765 }
747- let unresolvedImports : string [ ] ;
766+ let unresolvedImports : string [ ] | undefined ;
748767 if ( file . resolvedModules ) {
749768 file . resolvedModules . forEach ( ( resolvedModule , name ) => {
750769 // pick unresolved non-relative names
@@ -760,11 +779,17 @@ namespace ts.server {
760779 trimmed = trimmed . substr ( 0 , i ) ;
761780 }
762781 ( unresolvedImports || ( unresolvedImports = [ ] ) ) . push ( trimmed ) ;
763- result . push ( trimmed ) ;
782+ ( result || ( result = [ ] ) ) . push ( trimmed ) ;
764783 }
765784 } ) ;
766785 }
767- this . cachedUnresolvedImportsPerFile . set ( file . path , unresolvedImports || emptyArray ) ;
786+ if ( unresolvedImports ) {
787+ this . cachedUnresolvedImportsPerFile . set ( file . path , unresolvedImports ) ;
788+ }
789+ else {
790+ this . filesWithNoUnresolvedImports . set ( file . path , true ) ;
791+ }
792+ return result ;
768793
769794 function isAmbientlyDeclaredModule ( name : string ) {
770795 return ambientModules . some ( m => m === name ) ;
@@ -778,7 +803,7 @@ namespace ts.server {
778803 updateGraph ( ) : boolean {
779804 this . resolutionCache . startRecordingFilesWithChangedResolutions ( ) ;
780805
781- let hasChanges = this . updateGraphWorker ( ) ;
806+ const hasChanges = this . updateGraphWorker ( ) ;
782807 const hasMoreOrLessScriptInfos = this . hasMoreOrLessScriptInfos ;
783808 this . hasMoreOrLessScriptInfos = false ;
784809
@@ -787,6 +812,7 @@ namespace ts.server {
787812 for ( const file of changedFiles ) {
788813 // delete cached information for changed files
789814 this . cachedUnresolvedImportsPerFile . delete ( file ) ;
815+ this . filesWithNoUnresolvedImports . delete ( file ) ;
790816 }
791817
792818 // update builder only if language service is enabled
@@ -799,20 +825,15 @@ namespace ts.server {
799825 // (can reuse cached imports for files that were not changed)
800826 // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch
801827 if ( hasChanges || changedFiles . length ) {
802- const result : string [ ] = [ ] ;
828+ let result : string [ ] | undefined ;
803829 const ambientModules = this . program . getTypeChecker ( ) . getAmbientModules ( ) . map ( mod => stripQuotes ( mod . getName ( ) ) ) ;
804830 for ( const sourceFile of this . program . getSourceFiles ( ) ) {
805- this . extractUnresolvedImportsFromSourceFile ( sourceFile , result , ambientModules ) ;
831+ result = this . extractUnresolvedImportsFromSourceFile ( sourceFile , result , ambientModules ) ;
806832 }
807- this . lastCachedUnresolvedImportsList = toDeduplicatedSortedArray ( result ) ;
833+ this . lastCachedUnresolvedImportsList = result ? toDeduplicatedSortedArray ( result ) : emptyArray ;
808834 }
809835
810- const cachedTypings = this . projectService . typingsCache . getTypingsForProject ( this , this . lastCachedUnresolvedImportsList , hasMoreOrLessScriptInfos ) ;
811- if ( ! arrayIsEqualTo ( this . typingFiles , cachedTypings ) ) {
812- this . typingFiles = cachedTypings ;
813- this . markAsDirty ( ) ;
814- hasChanges = this . updateGraphWorker ( ) || hasChanges ;
815- }
836+ this . projectService . typingsCache . enqueueInstallTypingsForProject ( this , this . lastCachedUnresolvedImportsList , hasMoreOrLessScriptInfos ) ;
816837 }
817838 else {
818839 this . lastCachedUnresolvedImportsList = undefined ;
@@ -824,6 +845,13 @@ namespace ts.server {
824845 return ! hasChanges ;
825846 }
826847
848+ /*@internal */
849+ updateTypingFiles ( typingFiles : SortedReadonlyArray < string > ) {
850+ this . typingFiles = typingFiles ;
851+ // Invalidate files with unresolved imports
852+ this . resolutionCache . setFilesWithInvalidatedNonRelativeUnresolvedImports ( this . cachedUnresolvedImportsPerFile ) ;
853+ }
854+
827855 /* @internal */
828856 getCurrentProgram ( ) {
829857 return this . program ;
@@ -959,15 +987,14 @@ namespace ts.server {
959987 setCompilerOptions ( compilerOptions : CompilerOptions ) {
960988 if ( compilerOptions ) {
961989 compilerOptions . allowNonTsExtensions = true ;
962- if ( changesAffectModuleResolution ( this . compilerOptions , compilerOptions ) ) {
963- // reset cached unresolved imports if changes in compiler options affected module resolution
964- this . cachedUnresolvedImportsPerFile . clear ( ) ;
965- this . lastCachedUnresolvedImportsList = undefined ;
966- }
967990 const oldOptions = this . compilerOptions ;
968991 this . compilerOptions = compilerOptions ;
969992 this . setInternalCompilerOptionsForEmittingJsFiles ( ) ;
970993 if ( changesAffectModuleResolution ( oldOptions , compilerOptions ) ) {
994+ // reset cached unresolved imports if changes in compiler options affected module resolution
995+ this . cachedUnresolvedImportsPerFile . clear ( ) ;
996+ this . filesWithNoUnresolvedImports . clear ( ) ;
997+ this . lastCachedUnresolvedImportsList = undefined ;
971998 this . resolutionCache . clear ( ) ;
972999 }
9731000 this . markAsDirty ( ) ;
0 commit comments