@@ -45,7 +45,7 @@ namespace ts {
45
45
/**
46
46
* Newly computed visible to outside referencedSet
47
47
*/
48
- currentAffectedFilesExportedModulesMap ?: Readonly < BuilderState . ComputingExportedModulesMap > | undefined ;
48
+ currentAffectedFilesExportedModulesMap ?: BuilderState . ReadonlyManyToManyPathMap | undefined ;
49
49
/**
50
50
* True if the semantic diagnostics were copied from the old state
51
51
*/
@@ -113,8 +113,10 @@ namespace ts {
113
113
currentAffectedFilesSignatures : ESMap < Path , string > | undefined ;
114
114
/**
115
115
* 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.
116
118
*/
117
- currentAffectedFilesExportedModulesMap : BuilderState . ComputingExportedModulesMap | undefined ;
119
+ currentAffectedFilesExportedModulesMap : BuilderState . ManyToManyPathMap | undefined ;
118
120
/**
119
121
* Already seen affected files
120
122
*/
@@ -212,7 +214,7 @@ namespace ts {
212
214
const copyLibFileDiagnostics = copyDeclarationFileDiagnostics && ! compilerOptions . skipDefaultLibCheck === ! oldCompilerOptions ! . skipDefaultLibCheck ;
213
215
state . fileInfos . forEach ( ( info , sourceFilePath ) => {
214
216
let oldInfo : Readonly < BuilderState . FileInfo > | undefined ;
215
- let newReferences : BuilderState . ReferencedSet | undefined ;
217
+ let newReferences : ReadonlySet < Path > | undefined ;
216
218
217
219
// if not using old state, every file is changed
218
220
if ( ! useOldState ||
@@ -221,7 +223,7 @@ namespace ts {
221
223
// versions dont match
222
224
oldInfo . version !== info . version ||
223
225
// 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 ) ) ||
225
227
// Referenced file was deleted in the new program
226
228
newReferences && forEachKey ( newReferences , path => ! state . fileInfos . has ( path ) && oldState ! . fileInfos . has ( path ) ) ) {
227
229
// 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 {
311
313
newState . affectedFilesIndex = state . affectedFilesIndex ;
312
314
newState . currentChangedFilePath = state . currentChangedFilePath ;
313
315
newState . currentAffectedFilesSignatures = state . currentAffectedFilesSignatures && new Map ( state . currentAffectedFilesSignatures ) ;
314
- newState . currentAffectedFilesExportedModulesMap = state . currentAffectedFilesExportedModulesMap && new Map ( state . currentAffectedFilesExportedModulesMap ) ;
316
+ newState . currentAffectedFilesExportedModulesMap = state . currentAffectedFilesExportedModulesMap ?. clone ( ) ;
315
317
newState . seenAffectedFiles = state . seenAffectedFiles && new Set ( state . seenAffectedFiles ) ;
316
318
newState . cleanedDiagnosticsOfLibFiles = state . cleanedDiagnosticsOfLibFiles ;
317
319
newState . semanticDiagnosticsFromOldState = state . semanticDiagnosticsFromOldState && new Set ( state . semanticDiagnosticsFromOldState ) ;
@@ -384,7 +386,7 @@ namespace ts {
384
386
// Get next batch of affected files
385
387
if ( ! state . currentAffectedFilesSignatures ) state . currentAffectedFilesSignatures = new Map ( ) ;
386
388
if ( state . exportedModulesMap ) {
387
- if ( ! state . currentAffectedFilesExportedModulesMap ) state . currentAffectedFilesExportedModulesMap = new Map ( ) ;
389
+ state . currentAffectedFilesExportedModulesMap ||= BuilderState . createManyToManyPathMap ( ) ;
388
390
}
389
391
state . affectedFiles = BuilderState . getFilesAffectedBy ( state , program , nextKey . value , cancellationToken , computeHash , state . currentAffectedFilesSignatures , state . currentAffectedFilesExportedModulesMap ) ;
390
392
state . currentChangedFilePath = nextKey . value ;
@@ -465,7 +467,7 @@ namespace ts {
465
467
* Handle the dts may change, so they need to be added to pending emit if dts emit is enabled,
466
468
* Also we need to make sure signature is updated for these files
467
469
*/
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 {
469
471
removeSemanticDiagnosticsOf ( state , path ) ;
470
472
471
473
if ( ! state . changedFilesSet . has ( path ) ) {
@@ -544,36 +546,36 @@ namespace ts {
544
546
}
545
547
546
548
Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
549
+
547
550
const seenFileAndExportsOfFile = new Set < string > ( ) ;
548
551
// Go through exported modules from cache first
549
552
// 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 =>
553
554
forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
554
555
) ;
555
556
556
557
// 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 ) &&
560
562
forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
561
563
) ;
562
564
}
563
565
564
566
/**
565
567
* Iterate on files referencing referencedPath
566
568
*/
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 )
570
572
) ;
571
573
}
572
574
573
575
/**
574
576
* fn on file and iterate on anything that exports this file
575
577
*/
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 {
577
579
if ( ! tryAddToSet ( seenFileAndExportsOfFile , filePath ) ) {
578
580
return ;
579
581
}
@@ -583,23 +585,20 @@ namespace ts {
583
585
Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
584
586
// Go through exported modules from cache first
585
587
// 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 =>
589
589
forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
590
590
) ;
591
591
592
592
// 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 ) &&
596
597
forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
597
598
) ;
598
599
599
600
// 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 =>
603
602
! seenFileAndExportsOfFile . has ( referencingFilePath ) && // Not already removed diagnostic file
604
603
fn ( state , referencingFilePath ) // Dont add to seen since this is not yet done with the export removal
605
604
) ;
@@ -756,18 +755,26 @@ namespace ts {
756
755
if ( state . referencedMap ) {
757
756
referencedMap = arrayFrom ( state . referencedMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) . map ( key => [
758
757
toFileId ( key ) ,
759
- toFileIdListId ( state . referencedMap ! . get ( key ) ! )
758
+ toFileIdListId ( state . referencedMap ! . getValues ( key ) ! )
760
759
] ) ;
761
760
}
762
761
763
762
let exportedModulesMap : ProgramBuildInfoReferencedMap | undefined ;
764
763
if ( state . exportedModulesMap ) {
765
764
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
+
767
776
// 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 ) ! ) ] ;
771
778
} ) ;
772
779
}
773
780
@@ -1251,8 +1258,8 @@ namespace ts {
1251
1258
const state : ReusableBuilderProgramState = {
1252
1259
fileInfos,
1253
1260
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 ) ,
1256
1263
semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => toFilePath ( isNumber ( value ) ? value : value [ 0 ] ) , value => isNumber ( value ) ? emptyArray : value [ 1 ] ) ,
1257
1264
hasReusableDiagnostic : true ,
1258
1265
affectedFilesPendingEmit : map ( program . affectedFilesPendingEmit , value => toFilePath ( value [ 0 ] ) ) ,
@@ -1300,8 +1307,16 @@ namespace ts {
1300
1307
return filePathsSetList ! [ fileIdsListId - 1 ] ;
1301
1308
}
1302
1309
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 ;
1305
1320
}
1306
1321
}
1307
1322
0 commit comments