@@ -241,10 +241,7 @@ namespace ts {
241241 oldCompilerOptions . declarationDir !== compilerOptions . declarationDir ||
242242 ( oldCompilerOptions . outFile || oldCompilerOptions . out ) !== ( compilerOptions . outFile || compilerOptions . out ) ) ) {
243243 // Add all files to affectedFilesPendingEmit since emit changed
244- state . affectedFilesPendingEmit = concatenate ( state . affectedFilesPendingEmit , newProgram . getSourceFiles ( ) . map ( f => f . path ) ) ;
245- if ( state . affectedFilesPendingEmitIndex === undefined ) {
246- state . affectedFilesPendingEmitIndex = 0 ;
247- }
244+ addToAffectedFilesPendingEmit ( state , newProgram . getSourceFiles ( ) . map ( f => f . path ) ) ;
248245 Debug . assert ( state . seenAffectedFiles === undefined ) ;
249246 state . seenAffectedFiles = createMap < true > ( ) ;
250247 }
@@ -343,6 +340,7 @@ namespace ts {
343340 // Set the next affected file as seen and remove the cached semantic diagnostics
344341 state . affectedFilesIndex = affectedFilesIndex ;
345342 cleanSemanticDiagnosticsOfAffectedFile ( state , affectedFile ) ;
343+ handleDtsMayChangeOfAffectedFile ( state , affectedFile )
346344 return affectedFile ;
347345 }
348346 seenAffectedFiles . set ( affectedFile . path , true ) ;
@@ -433,7 +431,55 @@ namespace ts {
433431
434432 // If there was change in signature for the changed file,
435433 // then delete the semantic diagnostics for files that are affected by using exports of this module
434+ forEachReferencingModulesOfExportOfAffectedFile ( state , affectedFile , removeSemanticDiagnosticsOf ) ;
435+ }
436436
437+ /**
438+ * Removes semantic diagnostics for path and
439+ * returns true if there are no more semantic diagnostics from the old state
440+ */
441+ function removeSemanticDiagnosticsOf ( state : BuilderProgramState , path : Path ) {
442+ if ( ! state . semanticDiagnosticsFromOldState ) {
443+ return true ;
444+ }
445+ state . semanticDiagnosticsFromOldState . delete ( path ) ;
446+ state . semanticDiagnosticsPerFile ! . delete ( path ) ;
447+ return ! state . semanticDiagnosticsFromOldState . size ;
448+ }
449+
450+ /**
451+ * Add files, that are referencing modules that export entities from affected file as pending emit since dts may change
452+ * Similar to cleanSemanticDiagnosticsOfAffectedFile
453+ */
454+ function handleDtsMayChangeOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile ) {
455+ // If not dts emit, nothing more to do
456+ if ( ! getEmitDeclarations ( state . compilerOptions ) ) {
457+ return ;
458+ }
459+
460+ // If affected files is everything except default librarry, then nothing more to do
461+ if ( state . allFilesExcludingDefaultLibraryFile === state . affectedFiles ) {
462+ return ;
463+ }
464+
465+ // If there was change in signature (dts output) for the changed file,
466+ // then only we need to handle pending file emit
467+ if ( ! state . exportedModulesMap || state . affectedFiles ! . length === 1 || ! state . changedFilesSet . has ( affectedFile . path ) ) {
468+ return ;
469+ }
470+
471+ forEachReferencingModulesOfExportOfAffectedFile ( state , affectedFile , ( state , filePath ) => {
472+ addToAffectedFilesPendingEmit ( state , [ filePath ] ) ;
473+ return false ;
474+ } ) ;
475+ }
476+
477+ /**
478+ * Iterate on referencing modules that export entities from affected file
479+ */
480+ function forEachReferencingModulesOfExportOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile , fn : ( state : BuilderProgramState , filePath : Path ) => boolean ) {
481+ // If there was change in signature (dts output) for the changed file,
482+ // then only we need to handle pending file emit
437483 if ( ! state . exportedModulesMap || state . affectedFiles ! . length === 1 || ! state . changedFilesSet . has ( affectedFile . path ) ) {
438484 return ;
439485 }
@@ -445,7 +491,7 @@ namespace ts {
445491 if ( forEachEntry ( state . currentAffectedFilesExportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
446492 exportedModules &&
447493 exportedModules . has ( affectedFile . path ) &&
448- removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path , seenFileAndExportsOfFile )
494+ forEachFilesReferencingPath ( state , exportedFromPath as Path , seenFileAndExportsOfFile , fn )
449495 ) ) {
450496 return ;
451497 }
@@ -454,29 +500,28 @@ namespace ts {
454500 forEachEntry ( state . exportedModulesMap , ( exportedModules , exportedFromPath ) =>
455501 ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
456502 exportedModules . has ( affectedFile . path ) &&
457- removeSemanticDiagnosticsOfFilesReferencingPath ( state , exportedFromPath as Path , seenFileAndExportsOfFile )
503+ forEachFilesReferencingPath ( state , exportedFromPath as Path , seenFileAndExportsOfFile , fn )
458504 ) ;
459505 }
460506
461507 /**
462- * removes the semantic diagnostics of files referencing referencedPath and
463- * returns true if there are no more semantic diagnostics from old state
508+ * Iterate on files referencing referencedPath
464509 */
465- function removeSemanticDiagnosticsOfFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path , seenFileAndExportsOfFile : Map < true > ) {
510+ function forEachFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path , seenFileAndExportsOfFile : Map < true > , fn : ( state : BuilderProgramState , filePath : Path ) => boolean ) {
466511 return forEachEntry ( state . referencedMap ! , ( referencesInFile , filePath ) =>
467- referencesInFile . has ( referencedPath ) && removeSemanticDiagnosticsOfFileAndExportsOfFile ( state , filePath as Path , seenFileAndExportsOfFile )
512+ referencesInFile . has ( referencedPath ) && forEachFileAndExportsOfFile ( state , filePath as Path , seenFileAndExportsOfFile , fn )
468513 ) ;
469514 }
470515
471516 /**
472- * Removes semantic diagnostics of file and anything that exports this file
517+ * fn on file and iterate on anything that exports this file
473518 */
474- function removeSemanticDiagnosticsOfFileAndExportsOfFile ( state : BuilderProgramState , filePath : Path , seenFileAndExportsOfFile : Map < true > ) : boolean {
519+ function forEachFileAndExportsOfFile ( state : BuilderProgramState , filePath : Path , seenFileAndExportsOfFile : Map < true > , fn : ( state : BuilderProgramState , filePath : Path ) => boolean ) : boolean {
475520 if ( ! addToSeen ( seenFileAndExportsOfFile , filePath ) ) {
476521 return false ;
477522 }
478523
479- if ( removeSemanticDiagnosticsOf ( state , filePath ) ) {
524+ if ( fn ( state , filePath ) ) {
480525 // If there are no more diagnostics from old cache, done
481526 return true ;
482527 }
@@ -487,7 +532,7 @@ namespace ts {
487532 if ( forEachEntry ( state . currentAffectedFilesExportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
488533 exportedModules &&
489534 exportedModules . has ( filePath ) &&
490- removeSemanticDiagnosticsOfFileAndExportsOfFile ( state , exportedFromPath as Path , seenFileAndExportsOfFile )
535+ forEachFileAndExportsOfFile ( state , exportedFromPath as Path , seenFileAndExportsOfFile , fn )
491536 ) ) {
492537 return true ;
493538 }
@@ -496,7 +541,7 @@ namespace ts {
496541 if ( forEachEntry ( state . exportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
497542 ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
498543 exportedModules . has ( filePath ) &&
499- removeSemanticDiagnosticsOfFileAndExportsOfFile ( state , exportedFromPath as Path , seenFileAndExportsOfFile )
544+ forEachFileAndExportsOfFile ( state , exportedFromPath as Path , seenFileAndExportsOfFile , fn )
500545 ) ) {
501546 return true ;
502547 }
@@ -505,22 +550,10 @@ namespace ts {
505550 return ! ! forEachEntry ( state . referencedMap ! , ( referencesInFile , referencingFilePath ) =>
506551 referencesInFile . has ( filePath ) &&
507552 ! seenFileAndExportsOfFile . has ( referencingFilePath ) && // Not already removed diagnostic file
508- removeSemanticDiagnosticsOf ( state , referencingFilePath as Path ) // Dont add to seen since this is not yet done with the export removal
553+ fn ( state , referencingFilePath as Path ) // Dont add to seen since this is not yet done with the export removal
509554 ) ;
510555 }
511556
512- /**
513- * Removes semantic diagnostics for path and
514- * returns true if there are no more semantic diagnostics from the old state
515- */
516- function removeSemanticDiagnosticsOf ( state : BuilderProgramState , path : Path ) {
517- if ( ! state . semanticDiagnosticsFromOldState ) {
518- return true ;
519- }
520- state . semanticDiagnosticsFromOldState . delete ( path ) ;
521- state . semanticDiagnosticsPerFile ! . delete ( path ) ;
522- return ! state . semanticDiagnosticsFromOldState . size ;
523- }
524557
525558 /**
526559 * This is called after completing operation on the next affected file.
@@ -929,14 +962,7 @@ namespace ts {
929962
930963 // In case of emit builder, cache the files to be emitted
931964 if ( affectedFilesPendingEmit ) {
932- state . affectedFilesPendingEmit = concatenate ( state . affectedFilesPendingEmit , affectedFilesPendingEmit ) ;
933- // affectedFilesPendingEmitIndex === undefined
934- // - means the emit state.affectedFilesPendingEmit was undefined before adding current affected files
935- // so start from 0 as array would be affectedFilesPendingEmit
936- // else, continue to iterate from existing index, the current set is appended to existing files
937- if ( state . affectedFilesPendingEmitIndex === undefined ) {
938- state . affectedFilesPendingEmitIndex = 0 ;
939- }
965+ addToAffectedFilesPendingEmit ( state , affectedFilesPendingEmit ) ;
940966 }
941967
942968 let diagnostics : Diagnostic [ ] | undefined ;
@@ -947,6 +973,17 @@ namespace ts {
947973 }
948974 }
949975
976+ function addToAffectedFilesPendingEmit ( state : BuilderProgramState , affectedFilesPendingEmit : readonly Path [ ] ) {
977+ state . affectedFilesPendingEmit = concatenate ( state . affectedFilesPendingEmit , affectedFilesPendingEmit ) ;
978+ // affectedFilesPendingEmitIndex === undefined
979+ // - means the emit state.affectedFilesPendingEmit was undefined before adding current affected files
980+ // so start from 0 as array would be affectedFilesPendingEmit
981+ // else, continue to iterate from existing index, the current set is appended to existing files
982+ if ( state . affectedFilesPendingEmitIndex === undefined ) {
983+ state . affectedFilesPendingEmitIndex = 0 ;
984+ }
985+ }
986+
950987 function getMapOfReferencedSet ( mapLike : MapLike < ReadonlyArray < string > > | undefined ) : ReadonlyMap < BuilderState . ReferencedSet > | undefined {
951988 if ( ! mapLike ) return undefined ;
952989 const map = createMap < BuilderState . ReferencedSet > ( ) ;
0 commit comments