@@ -45,7 +45,7 @@ namespace ts {
4545 /**
4646 * Newly computed visible to outside referencedSet
4747 */
48- currentAffectedFilesExportedModulesMap ?: Readonly < BuilderState . ComputingExportedModulesMap > | undefined ;
48+ currentAffectedFilesExportedModulesMap ?: BuilderState . ReadonlyManyToManyPathMap | undefined ;
4949 /**
5050 * True if the semantic diagnostics were copied from the old state
5151 */
@@ -113,8 +113,10 @@ namespace ts {
113113 currentAffectedFilesSignatures : ESMap < Path , string > | undefined ;
114114 /**
115115 * Newly computed visible to outside referencedSet
116+ * We need to store the updates separately in case the in-progress build is cancelled
117+ * and we need to roll back.
116118 */
117- currentAffectedFilesExportedModulesMap : BuilderState . ComputingExportedModulesMap | undefined ;
119+ currentAffectedFilesExportedModulesMap : BuilderState . ManyToManyPathMap | undefined ;
118120 /**
119121 * Already seen affected files
120122 */
@@ -212,7 +214,7 @@ namespace ts {
212214 const copyLibFileDiagnostics = copyDeclarationFileDiagnostics && ! compilerOptions . skipDefaultLibCheck === ! oldCompilerOptions ! . skipDefaultLibCheck ;
213215 state . fileInfos . forEach ( ( info , sourceFilePath ) => {
214216 let oldInfo : Readonly < BuilderState . FileInfo > | undefined ;
215- let newReferences : BuilderState . ReferencedSet | undefined ;
217+ let newReferences : ReadonlySet < Path > | undefined ;
216218
217219 // if not using old state, every file is changed
218220 if ( ! useOldState ||
@@ -221,7 +223,7 @@ namespace ts {
221223 // versions dont match
222224 oldInfo . version !== info . version ||
223225 // Referenced files changed
224- ! hasSameKeys ( newReferences = referencedMap && referencedMap . get ( sourceFilePath ) , oldReferencedMap && oldReferencedMap . get ( sourceFilePath ) ) ||
226+ ! hasSameKeys ( newReferences = referencedMap && referencedMap . getValues ( sourceFilePath ) , oldReferencedMap && oldReferencedMap . getValues ( sourceFilePath ) ) ||
225227 // Referenced file was deleted in the new program
226228 newReferences && forEachKey ( newReferences , path => ! state . fileInfos . has ( path ) && oldState ! . fileInfos . has ( path ) ) ) {
227229 // Register file as changed file and do not copy semantic diagnostics, since all changed files need to be re-evaluated
@@ -311,7 +313,7 @@ namespace ts {
311313 newState . affectedFilesIndex = state . affectedFilesIndex ;
312314 newState . currentChangedFilePath = state . currentChangedFilePath ;
313315 newState . currentAffectedFilesSignatures = state . currentAffectedFilesSignatures && new Map ( state . currentAffectedFilesSignatures ) ;
314- newState . currentAffectedFilesExportedModulesMap = state . currentAffectedFilesExportedModulesMap && new Map ( state . currentAffectedFilesExportedModulesMap ) ;
316+ newState . currentAffectedFilesExportedModulesMap = state . currentAffectedFilesExportedModulesMap ?. clone ( ) ;
315317 newState . seenAffectedFiles = state . seenAffectedFiles && new Set ( state . seenAffectedFiles ) ;
316318 newState . cleanedDiagnosticsOfLibFiles = state . cleanedDiagnosticsOfLibFiles ;
317319 newState . semanticDiagnosticsFromOldState = state . semanticDiagnosticsFromOldState && new Set ( state . semanticDiagnosticsFromOldState ) ;
@@ -384,7 +386,7 @@ namespace ts {
384386 // Get next batch of affected files
385387 if ( ! state . currentAffectedFilesSignatures ) state . currentAffectedFilesSignatures = new Map ( ) ;
386388 if ( state . exportedModulesMap ) {
387- if ( ! state . currentAffectedFilesExportedModulesMap ) state . currentAffectedFilesExportedModulesMap = new Map ( ) ;
389+ state . currentAffectedFilesExportedModulesMap ||= BuilderState . createManyToManyPathMap ( ) ;
388390 }
389391 state . affectedFiles = BuilderState . getFilesAffectedBy ( state , program , nextKey . value , cancellationToken , computeHash , state . currentAffectedFilesSignatures , state . currentAffectedFilesExportedModulesMap ) ;
390392 state . currentChangedFilePath = nextKey . value ;
@@ -465,7 +467,7 @@ namespace ts {
465467 * Handle the dts may change, so they need to be added to pending emit if dts emit is enabled,
466468 * Also we need to make sure signature is updated for these files
467469 */
468- function handleDtsMayChangeOf ( state : BuilderProgramState , path : Path , cancellationToken : CancellationToken | undefined , computeHash : BuilderState . ComputeHash ) {
470+ function handleDtsMayChangeOf ( state : BuilderProgramState , path : Path , cancellationToken : CancellationToken | undefined , computeHash : BuilderState . ComputeHash ) : void {
469471 removeSemanticDiagnosticsOf ( state , path ) ;
470472
471473 if ( ! state . changedFilesSet . has ( path ) ) {
@@ -544,36 +546,36 @@ namespace ts {
544546 }
545547
546548 Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
549+
547550 const seenFileAndExportsOfFile = new Set < string > ( ) ;
548551 // Go through exported modules from cache first
549552 // If exported modules has path, all files referencing file exported from are affected
550- forEachEntry ( state . currentAffectedFilesExportedModulesMap , ( exportedModules , exportedFromPath ) =>
551- exportedModules &&
552- exportedModules . has ( affectedFile . resolvedPath ) &&
553+ state . currentAffectedFilesExportedModulesMap . getKeys ( affectedFile . resolvedPath ) ?. forEach ( exportedFromPath =>
553554 forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
554555 ) ;
555556
556557 // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
557- forEachEntry ( state . exportedModulesMap , ( exportedModules , exportedFromPath ) =>
558- ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
559- exportedModules . has ( affectedFile . resolvedPath ) &&
558+ state . exportedModulesMap . getKeys ( affectedFile . resolvedPath ) ?. forEach ( exportedFromPath =>
559+ // If the cache had an updated value, skip
560+ ! state . currentAffectedFilesExportedModulesMap ! . hasKey ( exportedFromPath ) &&
561+ ! state . currentAffectedFilesExportedModulesMap ! . deletedKeys ( ) ?. has ( exportedFromPath ) &&
560562 forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
561563 ) ;
562564 }
563565
564566 /**
565567 * Iterate on files referencing referencedPath
566568 */
567- function forEachFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) {
568- forEachEntry ( state . referencedMap ! , ( referencesInFile , filePath ) =>
569- referencesInFile . has ( referencedPath ) && forEachFileAndExportsOfFile ( state , filePath , seenFileAndExportsOfFile , fn )
569+ function forEachFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) : void {
570+ state . referencedMap ! . getKeys ( referencedPath ) ?. forEach ( filePath =>
571+ forEachFileAndExportsOfFile ( state , filePath , seenFileAndExportsOfFile , fn )
570572 ) ;
571573 }
572574
573575 /**
574576 * fn on file and iterate on anything that exports this file
575577 */
576- function forEachFileAndExportsOfFile ( state : BuilderProgramState , filePath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) {
578+ function forEachFileAndExportsOfFile ( state : BuilderProgramState , filePath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) : void {
577579 if ( ! tryAddToSet ( seenFileAndExportsOfFile , filePath ) ) {
578580 return ;
579581 }
@@ -583,23 +585,20 @@ namespace ts {
583585 Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
584586 // Go through exported modules from cache first
585587 // If exported modules has path, all files referencing file exported from are affected
586- forEachEntry ( state . currentAffectedFilesExportedModulesMap , ( exportedModules , exportedFromPath ) =>
587- exportedModules &&
588- exportedModules . has ( filePath ) &&
588+ state . currentAffectedFilesExportedModulesMap . getKeys ( filePath ) ?. forEach ( exportedFromPath =>
589589 forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
590590 ) ;
591591
592592 // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
593- forEachEntry ( state . exportedModulesMap ! , ( exportedModules , exportedFromPath ) =>
594- ! state . currentAffectedFilesExportedModulesMap ! . has ( exportedFromPath ) && // If we already iterated this through cache, ignore it
595- exportedModules . has ( filePath ) &&
593+ state . exportedModulesMap ! . getKeys ( filePath ) ?. forEach ( exportedFromPath =>
594+ // If the cache had an updated value, skip
595+ ! state . currentAffectedFilesExportedModulesMap ! . hasKey ( exportedFromPath ) &&
596+ ! state . currentAffectedFilesExportedModulesMap ! . deletedKeys ( ) ?. has ( exportedFromPath ) &&
596597 forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
597598 ) ;
598599
599600 // Remove diagnostics of files that import this file (without going to exports of referencing files)
600-
601- forEachEntry ( state . referencedMap ! , ( referencesInFile , referencingFilePath ) =>
602- referencesInFile . has ( filePath ) &&
601+ state . referencedMap ! . getKeys ( filePath ) ?. forEach ( referencingFilePath =>
603602 ! seenFileAndExportsOfFile . has ( referencingFilePath ) && // Not already removed diagnostic file
604603 fn ( state , referencingFilePath ) // Dont add to seen since this is not yet done with the export removal
605604 ) ;
@@ -756,18 +755,26 @@ namespace ts {
756755 if ( state . referencedMap ) {
757756 referencedMap = arrayFrom ( state . referencedMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) . map ( key => [
758757 toFileId ( key ) ,
759- toFileIdListId ( state . referencedMap ! . get ( key ) ! )
758+ toFileIdListId ( state . referencedMap ! . getValues ( key ) ! )
760759 ] ) ;
761760 }
762761
763762 let exportedModulesMap : ProgramBuildInfoReferencedMap | undefined ;
764763 if ( state . exportedModulesMap ) {
765764 exportedModulesMap = mapDefined ( arrayFrom ( state . exportedModulesMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) , key => {
766- const newValue = state . currentAffectedFilesExportedModulesMap && state . currentAffectedFilesExportedModulesMap . get ( key ) ;
765+ if ( state . currentAffectedFilesExportedModulesMap ) {
766+ if ( state . currentAffectedFilesExportedModulesMap . deletedKeys ( ) ?. has ( key ) ) {
767+ return undefined ;
768+ }
769+
770+ const newValue = state . currentAffectedFilesExportedModulesMap . getValues ( key ) ;
771+ if ( newValue ) {
772+ return [ toFileId ( key ) , toFileIdListId ( newValue ) ] ;
773+ }
774+ }
775+
767776 // Not in temporary cache, use existing value
768- if ( newValue === undefined ) return [ toFileId ( key ) , toFileIdListId ( state . exportedModulesMap ! . get ( key ) ! ) ] ;
769- // Value in cache and has updated value map, use that
770- else if ( newValue ) return [ toFileId ( key ) , toFileIdListId ( newValue ) ] ;
777+ return [ toFileId ( key ) , toFileIdListId ( state . exportedModulesMap ! . getValues ( key ) ! ) ] ;
771778 } ) ;
772779 }
773780
@@ -1251,8 +1258,8 @@ namespace ts {
12511258 const state : ReusableBuilderProgramState = {
12521259 fileInfos,
12531260 compilerOptions : program . options ? convertToOptionsWithAbsolutePaths ( program . options , toAbsolutePath ) : { } ,
1254- referencedMap : toMapOfReferencedSet ( program . referencedMap ) ,
1255- exportedModulesMap : toMapOfReferencedSet ( program . exportedModulesMap ) ,
1261+ referencedMap : toManyToManyPathMap ( program . referencedMap ) ,
1262+ exportedModulesMap : toManyToManyPathMap ( program . exportedModulesMap ) ,
12561263 semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => toFilePath ( isNumber ( value ) ? value : value [ 0 ] ) , value => isNumber ( value ) ? emptyArray : value [ 1 ] ) ,
12571264 hasReusableDiagnostic : true ,
12581265 affectedFilesPendingEmit : map ( program . affectedFilesPendingEmit , value => toFilePath ( value [ 0 ] ) ) ,
@@ -1300,8 +1307,16 @@ namespace ts {
13001307 return filePathsSetList ! [ fileIdsListId - 1 ] ;
13011308 }
13021309
1303- function toMapOfReferencedSet ( referenceMap : ProgramBuildInfoReferencedMap | undefined ) : ReadonlyESMap < Path , BuilderState . ReferencedSet > | undefined {
1304- return referenceMap && arrayToMap ( referenceMap , value => toFilePath ( value [ 0 ] ) , value => toFilePathsSet ( value [ 1 ] ) ) ;
1310+ function toManyToManyPathMap ( referenceMap : ProgramBuildInfoReferencedMap | undefined ) : BuilderState . ManyToManyPathMap | undefined {
1311+ if ( ! referenceMap ) {
1312+ return undefined ;
1313+ }
1314+
1315+ const map = BuilderState . createManyToManyPathMap ( ) ;
1316+ referenceMap . forEach ( ( [ fileId , fileIdListId ] ) =>
1317+ map . set ( toFilePath ( fileId ) , toFilePathsSet ( fileIdListId ) )
1318+ ) ;
1319+ return map ;
13051320 }
13061321 }
13071322
0 commit comments