@@ -434,25 +434,35 @@ namespace ts {
434
434
return undefined ;
435
435
}
436
436
437
+ function removeDiagnosticsOfLibraryFiles ( state : BuilderProgramState ) {
438
+ if ( ! state . cleanedDiagnosticsOfLibFiles ) {
439
+ state . cleanedDiagnosticsOfLibFiles = true ;
440
+ const program = Debug . checkDefined ( state . program ) ;
441
+ const options = program . getCompilerOptions ( ) ;
442
+ forEach ( program . getSourceFiles ( ) , f =>
443
+ program . isSourceFileDefaultLibrary ( f ) &&
444
+ ! skipTypeChecking ( f , options , program ) &&
445
+ removeSemanticDiagnosticsOf ( state , f . resolvedPath )
446
+ ) ;
447
+ }
448
+ }
449
+
437
450
/**
438
451
* Handles semantic diagnostics and dts emit for affectedFile and files, that are referencing modules that export entities from affected file
439
452
* This is because even though js emit doesnt change, dts emit / type used can change resulting in need for dts emit and js change
440
453
*/
441
- function handleDtsMayChangeOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile , cancellationToken : CancellationToken | undefined , computeHash : BuilderState . ComputeHash , host : BuilderProgramHost ) {
454
+ function handleDtsMayChangeOfAffectedFile (
455
+ state : BuilderProgramState ,
456
+ affectedFile : SourceFile ,
457
+ cancellationToken : CancellationToken | undefined ,
458
+ computeHash : BuilderState . ComputeHash ,
459
+ host : BuilderProgramHost ,
460
+ ) {
442
461
removeSemanticDiagnosticsOf ( state , affectedFile . resolvedPath ) ;
443
462
444
463
// If affected files is everything except default library, then nothing more to do
445
464
if ( state . allFilesExcludingDefaultLibraryFile === state . affectedFiles ) {
446
- if ( ! state . cleanedDiagnosticsOfLibFiles ) {
447
- state . cleanedDiagnosticsOfLibFiles = true ;
448
- const program = Debug . checkDefined ( state . program ) ;
449
- const options = program . getCompilerOptions ( ) ;
450
- forEach ( program . getSourceFiles ( ) , f =>
451
- program . isSourceFileDefaultLibrary ( f ) &&
452
- ! skipTypeChecking ( f , options , program ) &&
453
- removeSemanticDiagnosticsOf ( state , f . resolvedPath )
454
- ) ;
455
- }
465
+ removeDiagnosticsOfLibraryFiles ( state ) ;
456
466
// When a change affects the global scope, all files are considered to be affected without updating their signature
457
467
// That means when affected file is handled, its signature can be out of date
458
468
// To avoid this, ensure that we update the signature for any affected file in this scenario.
@@ -467,20 +477,22 @@ namespace ts {
467
477
) ;
468
478
return ;
469
479
}
470
- else {
471
- Debug . assert ( state . hasCalledUpdateShapeSignature . has ( affectedFile . resolvedPath ) || state . currentAffectedFilesSignatures ?. has ( affectedFile . resolvedPath ) , `Signature not updated for affected file: ${ affectedFile . fileName } ` ) ;
472
- }
473
-
474
- if ( ! state . compilerOptions . assumeChangesOnlyAffectDirectDependencies ) {
475
- forEachReferencingModulesOfExportOfAffectedFile ( state , affectedFile , ( state , path ) => handleDtsMayChangeOf ( state , path , cancellationToken , computeHash , host ) ) ;
476
- }
480
+ Debug . assert ( state . hasCalledUpdateShapeSignature . has ( affectedFile . resolvedPath ) || state . currentAffectedFilesSignatures ?. has ( affectedFile . resolvedPath ) , `Signature not updated for affected file: ${ affectedFile . fileName } ` ) ;
481
+ if ( state . compilerOptions . assumeChangesOnlyAffectDirectDependencies ) return ;
482
+ handleDtsMayChangeOfReferencingExportOfAffectedFile ( state , affectedFile , cancellationToken , computeHash , host ) ;
477
483
}
478
484
479
485
/**
480
486
* Handle the dts may change, so they need to be added to pending emit if dts emit is enabled,
481
487
* Also we need to make sure signature is updated for these files
482
488
*/
483
- function handleDtsMayChangeOf ( state : BuilderProgramState , path : Path , cancellationToken : CancellationToken | undefined , computeHash : BuilderState . ComputeHash , host : BuilderProgramHost ) : void {
489
+ function handleDtsMayChangeOf (
490
+ state : BuilderProgramState ,
491
+ path : Path ,
492
+ cancellationToken : CancellationToken | undefined ,
493
+ computeHash : BuilderState . ComputeHash ,
494
+ host : BuilderProgramHost
495
+ ) : void {
484
496
removeSemanticDiagnosticsOf ( state , path ) ;
485
497
486
498
if ( ! state . changedFilesSet . has ( path ) ) {
@@ -529,16 +541,61 @@ namespace ts {
529
541
return newSignature !== oldSignature ;
530
542
}
531
543
544
+ function forEachKeyOfExportedModulesMap < T > (
545
+ state : BuilderProgramState ,
546
+ filePath : Path ,
547
+ fn : ( exportedFromPath : Path ) => T | undefined ,
548
+ ) : T | undefined {
549
+ // Go through exported modules from cache first
550
+ let keys = state . currentAffectedFilesExportedModulesMap ! . getKeys ( filePath ) ;
551
+ const result = keys && forEachKey ( keys , fn ) ;
552
+ if ( result ) return result ;
553
+
554
+ // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
555
+ keys = state . exportedModulesMap ! . getKeys ( filePath ) ;
556
+ return keys && forEachKey ( keys , exportedFromPath =>
557
+ // If the cache had an updated value, skip
558
+ ! state . currentAffectedFilesExportedModulesMap ! . hasKey ( exportedFromPath ) &&
559
+ ! state . currentAffectedFilesExportedModulesMap ! . deletedKeys ( ) ?. has ( exportedFromPath ) ?
560
+ fn ( exportedFromPath ) :
561
+ undefined
562
+ ) ;
563
+ }
564
+
565
+ function handleDtsMayChangeOfGlobalScope (
566
+ state : BuilderProgramState ,
567
+ filePath : Path ,
568
+ cancellationToken : CancellationToken | undefined ,
569
+ computeHash : BuilderState . ComputeHash ,
570
+ host : BuilderProgramHost ,
571
+ ) : boolean {
572
+ if ( ! state . fileInfos . get ( filePath ) ?. affectsGlobalScope ) return false ;
573
+ // Every file needs to be handled
574
+ BuilderState . getAllFilesExcludingDefaultLibraryFile ( state , state . program ! , /*firstSourceFile*/ undefined )
575
+ . forEach ( file => handleDtsMayChangeOf (
576
+ state ,
577
+ file . resolvedPath ,
578
+ cancellationToken ,
579
+ computeHash ,
580
+ host ,
581
+ ) ) ;
582
+ removeDiagnosticsOfLibraryFiles ( state ) ;
583
+ return true ;
584
+ }
585
+
532
586
/**
533
- * Iterate on referencing modules that export entities from affected file
587
+ * Iterate on referencing modules that export entities from affected file and delete diagnostics and add pending emit
534
588
*/
535
- function forEachReferencingModulesOfExportOfAffectedFile ( state : BuilderProgramState , affectedFile : SourceFile , fn : ( state : BuilderProgramState , filePath : Path ) => void ) {
589
+ function handleDtsMayChangeOfReferencingExportOfAffectedFile (
590
+ state : BuilderProgramState ,
591
+ affectedFile : SourceFile ,
592
+ cancellationToken : CancellationToken | undefined ,
593
+ computeHash : BuilderState . ComputeHash ,
594
+ host : BuilderProgramHost
595
+ ) {
536
596
// If there was change in signature (dts output) for the changed file,
537
597
// then only we need to handle pending file emit
538
- if ( ! state . exportedModulesMap || ! state . changedFilesSet . has ( affectedFile . resolvedPath ) ) {
539
- return ;
540
- }
541
-
598
+ if ( ! state . exportedModulesMap || ! state . changedFilesSet . has ( affectedFile . resolvedPath ) ) return ;
542
599
if ( ! isChangedSignature ( state , affectedFile . resolvedPath ) ) return ;
543
600
544
601
// Since isolated modules dont change js files, files affected by change in signature is itself
@@ -551,7 +608,8 @@ namespace ts {
551
608
const currentPath = queue . pop ( ) ! ;
552
609
if ( ! seenFileNamesMap . has ( currentPath ) ) {
553
610
seenFileNamesMap . set ( currentPath , true ) ;
554
- fn ( state , currentPath ) ;
611
+ if ( handleDtsMayChangeOfGlobalScope ( state , currentPath , cancellationToken , computeHash , host ) ) return ;
612
+ handleDtsMayChangeOf ( state , currentPath , cancellationToken , computeHash , host ) ;
555
613
if ( isChangedSignature ( state , currentPath ) ) {
556
614
const currentSourceFile = Debug . checkDefined ( state . program ) . getSourceFileByPath ( currentPath ) ! ;
557
615
queue . push ( ...BuilderState . getReferencedByPaths ( state , currentSourceFile . resolvedPath ) ) ;
@@ -561,65 +619,69 @@ namespace ts {
561
619
}
562
620
563
621
Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
564
-
565
622
const seenFileAndExportsOfFile = new Set < string > ( ) ;
566
623
// Go through exported modules from cache first
567
624
// If exported modules has path, all files referencing file exported from are affected
568
- state . currentAffectedFilesExportedModulesMap . getKeys ( affectedFile . resolvedPath ) ?. forEach ( exportedFromPath =>
569
- forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
570
- ) ;
571
-
572
- // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
573
- state . exportedModulesMap . getKeys ( affectedFile . resolvedPath ) ?. forEach ( exportedFromPath =>
574
- // If the cache had an updated value, skip
575
- ! state . currentAffectedFilesExportedModulesMap ! . hasKey ( exportedFromPath ) &&
576
- ! state . currentAffectedFilesExportedModulesMap ! . deletedKeys ( ) ?. has ( exportedFromPath ) &&
577
- forEachFilesReferencingPath ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
578
- ) ;
579
- }
580
-
581
- /**
582
- * Iterate on files referencing referencedPath
583
- */
584
- function forEachFilesReferencingPath ( state : BuilderProgramState , referencedPath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) : void {
585
- state . referencedMap ! . getKeys ( referencedPath ) ?. forEach ( filePath =>
586
- forEachFileAndExportsOfFile ( state , filePath , seenFileAndExportsOfFile , fn )
587
- ) ;
625
+ forEachKeyOfExportedModulesMap ( state , affectedFile . resolvedPath , exportedFromPath => {
626
+ if ( handleDtsMayChangeOfGlobalScope ( state , exportedFromPath , cancellationToken , computeHash , host ) ) return true ;
627
+ const references = state . referencedMap ! . getKeys ( exportedFromPath ) ;
628
+ return references && forEachKey ( references , filePath =>
629
+ handleDtsMayChangeOfFileAndExportsOfFile (
630
+ state ,
631
+ filePath ,
632
+ seenFileAndExportsOfFile ,
633
+ cancellationToken ,
634
+ computeHash ,
635
+ host ,
636
+ )
637
+ ) ;
638
+ } ) ;
588
639
}
589
640
590
641
/**
591
- * fn on file and iterate on anything that exports this file
642
+ * handle dts and semantic diagnostics on file and iterate on anything that exports this file
643
+ * return true when all work is done and we can exit handling dts emit and semantic diagnostics
592
644
*/
593
- function forEachFileAndExportsOfFile ( state : BuilderProgramState , filePath : Path , seenFileAndExportsOfFile : Set < string > , fn : ( state : BuilderProgramState , filePath : Path ) => void ) : void {
594
- if ( ! tryAddToSet ( seenFileAndExportsOfFile , filePath ) ) {
595
- return ;
596
- }
597
-
598
- fn ( state , filePath ) ;
599
-
645
+ function handleDtsMayChangeOfFileAndExportsOfFile (
646
+ state : BuilderProgramState ,
647
+ filePath : Path ,
648
+ seenFileAndExportsOfFile : Set < string > ,
649
+ cancellationToken : CancellationToken | undefined ,
650
+ computeHash : BuilderState . ComputeHash ,
651
+ host : BuilderProgramHost ,
652
+ ) : boolean | undefined {
653
+ if ( ! tryAddToSet ( seenFileAndExportsOfFile , filePath ) ) return undefined ;
654
+
655
+ if ( handleDtsMayChangeOfGlobalScope ( state , filePath , cancellationToken , computeHash , host ) ) return true ;
656
+ handleDtsMayChangeOf ( state , filePath , cancellationToken , computeHash , host ) ;
600
657
Debug . assert ( ! ! state . currentAffectedFilesExportedModulesMap ) ;
601
- // Go through exported modules from cache first
602
- // If exported modules has path, all files referencing file exported from are affected
603
- state . currentAffectedFilesExportedModulesMap . getKeys ( filePath ) ?. forEach ( exportedFromPath =>
604
- forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
605
- ) ;
606
658
607
- // If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
608
- state . exportedModulesMap ! . getKeys ( filePath ) ?. forEach ( exportedFromPath =>
609
- // If the cache had an updated value, skip
610
- ! state . currentAffectedFilesExportedModulesMap ! . hasKey ( exportedFromPath ) &&
611
- ! state . currentAffectedFilesExportedModulesMap ! . deletedKeys ( ) ?. has ( exportedFromPath ) &&
612
- forEachFileAndExportsOfFile ( state , exportedFromPath , seenFileAndExportsOfFile , fn )
659
+ // If exported modules has path, all files referencing file exported from are affected
660
+ forEachKeyOfExportedModulesMap ( state , filePath , exportedFromPath =>
661
+ handleDtsMayChangeOfFileAndExportsOfFile (
662
+ state ,
663
+ exportedFromPath ,
664
+ seenFileAndExportsOfFile ,
665
+ cancellationToken ,
666
+ computeHash ,
667
+ host ,
668
+ )
613
669
) ;
614
670
615
671
// Remove diagnostics of files that import this file (without going to exports of referencing files)
616
672
state . referencedMap ! . getKeys ( filePath ) ?. forEach ( referencingFilePath =>
617
673
! seenFileAndExportsOfFile . has ( referencingFilePath ) && // Not already removed diagnostic file
618
- fn ( state , referencingFilePath ) // Dont add to seen since this is not yet done with the export removal
674
+ handleDtsMayChangeOf ( // Dont add to seen since this is not yet done with the export removal
675
+ state ,
676
+ referencingFilePath ,
677
+ cancellationToken ,
678
+ computeHash ,
679
+ host ,
680
+ )
619
681
) ;
682
+ return undefined ;
620
683
}
621
684
622
-
623
685
/**
624
686
* This is called after completing operation on the next affected file.
625
687
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly
0 commit comments