@@ -420,6 +420,8 @@ namespace ts {
420
420
}
421
421
}
422
422
423
+ const initialVersion = 1 ;
424
+
423
425
/**
424
426
* Creates the watch from the host for root files and compiler options
425
427
*/
@@ -429,19 +431,25 @@ namespace ts {
429
431
*/
430
432
export function createWatchProgram < T extends BuilderProgram > ( host : WatchCompilerHostOfConfigFile < T > ) : WatchOfConfigFile < T > ;
431
433
export function createWatchProgram < T extends BuilderProgram > ( host : WatchCompilerHostOfFilesAndCompilerOptions < T > & WatchCompilerHostOfConfigFile < T > ) : WatchOfFilesAndCompilerOptions < T > | WatchOfConfigFile < T > {
432
- interface HostFileInfo {
434
+ interface FilePresentOnHost {
433
435
version : number ;
434
436
sourceFile : SourceFile ;
435
437
fileWatcher : FileWatcher ;
436
438
}
439
+ type FileMissingOnHost = number ;
440
+ interface FilePresenceUnknownOnHost {
441
+ version : number ;
442
+ }
443
+ type FileMayBePresentOnHost = FilePresentOnHost | FilePresenceUnknownOnHost ;
444
+ type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost ;
437
445
438
446
let builderProgram : T ;
439
447
let reloadLevel : ConfigFileProgramReloadLevel ; // level to indicate if the program needs to be reloaded from config file/just filenames etc
440
448
let missingFilesMap : Map < FileWatcher > ; // Map of file watchers for the missing files
441
449
let watchedWildcardDirectories : Map < WildcardDirectoryWatcher > ; // map of watchers for the wild card directories in the config file
442
450
let timerToUpdateProgram : any ; // timer callback to recompile the program
443
451
444
- const sourceFilesCache = createMap < HostFileInfo | string > ( ) ; // Cache that stores the source file and version info
452
+ const sourceFilesCache = createMap < HostFileInfo > ( ) ; // Cache that stores the source file and version info
445
453
let missingFilePathsRequestedForRelease : Path [ ] ; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
446
454
let hasChangedCompilerOptions = false ; // True if the compiler options have changed between compilations
447
455
let hasChangedAutomaticTypeDirectiveNames = false ; // True if the automatic type directives have changed
@@ -480,14 +488,14 @@ namespace ts {
480
488
const watchFilePath = compilerOptions . extendedDiagnostics ? ts . addFilePathWatcherWithLogging : ts . addFilePathWatcher ;
481
489
const watchDirectoryWorker = compilerOptions . extendedDiagnostics ? ts . addDirectoryWatcherWithLogging : ts . addDirectoryWatcher ;
482
490
491
+ const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) ;
492
+ let newLine = updateNewLine ( ) ;
493
+
483
494
writeLog ( `Current directory: ${ currentDirectory } CaseSensitiveFileNames: ${ useCaseSensitiveFileNames } ` ) ;
484
495
if ( configFileName ) {
485
496
watchFile ( host , configFileName , scheduleProgramReload , writeLog ) ;
486
497
}
487
498
488
- const getCanonicalFileName = createGetCanonicalFileName ( useCaseSensitiveFileNames ) ;
489
- let newLine = updateNewLine ( ) ;
490
-
491
499
const compilerHost : CompilerHost & ResolutionCacheHost = {
492
500
// Members for CompilerHost
493
501
getSourceFile : ( fileName , languageVersion , onError ?, shouldCreateNewSourceFile ?) => getVersionedSourceFileByPath ( fileName , toPath ( fileName ) , languageVersion , onError , shouldCreateNewSourceFile ) ,
@@ -575,7 +583,9 @@ namespace ts {
575
583
576
584
// Compile the program
577
585
if ( loggingEnabled ) {
578
- writeLog ( `CreatingProgramWith::\n roots: ${ JSON . stringify ( rootFileNames ) } \n options: ${ JSON . stringify ( compilerOptions ) } ` ) ;
586
+ writeLog ( `CreatingProgramWith::` ) ;
587
+ writeLog ( ` roots: ${ JSON . stringify ( rootFileNames ) } ` ) ;
588
+ writeLog ( ` options: ${ JSON . stringify ( compilerOptions ) } ` ) ;
579
589
}
580
590
581
591
const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || ! program ;
@@ -627,11 +637,20 @@ namespace ts {
627
637
return ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ;
628
638
}
629
639
640
+ function isFileMissingOnHost ( hostSourceFile : HostFileInfo ) : hostSourceFile is FileMissingOnHost {
641
+ return typeof hostSourceFile === "number" ;
642
+ }
643
+
644
+ function isFilePresentOnHost ( hostSourceFile : FileMayBePresentOnHost ) : hostSourceFile is FilePresentOnHost {
645
+ return ! ! ( hostSourceFile as FilePresentOnHost ) . sourceFile ;
646
+ }
647
+
630
648
function fileExists ( fileName : string ) {
631
649
const path = toPath ( fileName ) ;
632
- const hostSourceFileInfo = sourceFilesCache . get ( path ) ;
633
- if ( hostSourceFileInfo !== undefined ) {
634
- return ! isString ( hostSourceFileInfo ) ;
650
+ // If file is missing on host from cache, we can definitely say file doesnt exist
651
+ // otherwise we need to ensure from the disk
652
+ if ( isFileMissingOnHost ( sourceFilesCache . get ( path ) ) ) {
653
+ return true ;
635
654
}
636
655
637
656
return directoryStructureHost . fileExists ( fileName ) ;
@@ -640,39 +659,42 @@ namespace ts {
640
659
function getVersionedSourceFileByPath ( fileName : string , path : Path , languageVersion : ScriptTarget , onError ?: ( message : string ) => void , shouldCreateNewSourceFile ?: boolean ) : SourceFile {
641
660
const hostSourceFile = sourceFilesCache . get ( path ) ;
642
661
// No source file on the host
643
- if ( isString ( hostSourceFile ) ) {
662
+ if ( isFileMissingOnHost ( hostSourceFile ) ) {
644
663
return undefined ;
645
664
}
646
665
647
666
// Create new source file if requested or the versions dont match
648
- if ( ! hostSourceFile || shouldCreateNewSourceFile || hostSourceFile . version . toString ( ) !== hostSourceFile . sourceFile . version ) {
667
+ if ( ! hostSourceFile || shouldCreateNewSourceFile || ! isFilePresentOnHost ( hostSourceFile ) || hostSourceFile . version . toString ( ) !== hostSourceFile . sourceFile . version ) {
649
668
const sourceFile = getNewSourceFile ( ) ;
650
669
if ( hostSourceFile ) {
651
670
if ( shouldCreateNewSourceFile ) {
652
671
hostSourceFile . version ++ ;
653
672
}
673
+
654
674
if ( sourceFile ) {
655
- hostSourceFile . sourceFile = sourceFile ;
675
+ // Set the source file and create file watcher now that file was present on the disk
676
+ ( hostSourceFile as FilePresentOnHost ) . sourceFile = sourceFile ;
656
677
sourceFile . version = hostSourceFile . version . toString ( ) ;
657
- if ( ! hostSourceFile . fileWatcher ) {
658
- hostSourceFile . fileWatcher = watchFilePath ( host , fileName , onSourceFileChange , path , writeLog ) ;
678
+ if ( ! ( hostSourceFile as FilePresentOnHost ) . fileWatcher ) {
679
+ ( hostSourceFile as FilePresentOnHost ) . fileWatcher = watchFilePath ( host , fileName , onSourceFileChange , path , writeLog ) ;
659
680
}
660
681
}
661
682
else {
662
683
// There is no source file on host any more, close the watch, missing file paths will track it
663
- hostSourceFile . fileWatcher . close ( ) ;
664
- sourceFilesCache . set ( path , hostSourceFile . version . toString ( ) ) ;
684
+ if ( isFilePresentOnHost ( hostSourceFile ) ) {
685
+ hostSourceFile . fileWatcher . close ( ) ;
686
+ }
687
+ sourceFilesCache . set ( path , hostSourceFile . version ) ;
665
688
}
666
689
}
667
690
else {
668
- let fileWatcher : FileWatcher ;
669
691
if ( sourceFile ) {
670
- sourceFile . version = "1" ;
671
- fileWatcher = watchFilePath ( host , fileName , onSourceFileChange , path , writeLog ) ;
672
- sourceFilesCache . set ( path , { sourceFile, version : 1 , fileWatcher } ) ;
692
+ sourceFile . version = initialVersion . toString ( ) ;
693
+ const fileWatcher = watchFilePath ( host , fileName , onSourceFileChange , path , writeLog ) ;
694
+ sourceFilesCache . set ( path , { sourceFile, version : initialVersion , fileWatcher } ) ;
673
695
}
674
696
else {
675
- sourceFilesCache . set ( path , "0" ) ;
697
+ sourceFilesCache . set ( path , initialVersion ) ;
676
698
}
677
699
}
678
700
return sourceFile ;
@@ -697,20 +719,22 @@ namespace ts {
697
719
}
698
720
}
699
721
700
- function removeSourceFile ( path : Path ) {
722
+ function nextSourceFileVersion ( path : Path ) {
701
723
const hostSourceFile = sourceFilesCache . get ( path ) ;
702
724
if ( hostSourceFile !== undefined ) {
703
- if ( ! isString ( hostSourceFile ) ) {
704
- hostSourceFile . fileWatcher . close ( ) ;
705
- resolutionCache . invalidateResolutionOfFile ( path ) ;
725
+ if ( isFileMissingOnHost ( hostSourceFile ) ) {
726
+ // The next version, lets set it as presence unknown file
727
+ sourceFilesCache . set ( path , { version : Number ( hostSourceFile ) + 1 } ) ;
728
+ }
729
+ else {
730
+ hostSourceFile . version ++ ;
706
731
}
707
- sourceFilesCache . delete ( path ) ;
708
732
}
709
733
}
710
734
711
735
function getSourceVersion ( path : Path ) : string {
712
736
const hostSourceFile = sourceFilesCache . get ( path ) ;
713
- return ! hostSourceFile || isString ( hostSourceFile ) ? undefined : hostSourceFile . version . toString ( ) ;
737
+ return ! hostSourceFile || isFileMissingOnHost ( hostSourceFile ) ? undefined : hostSourceFile . version . toString ( ) ;
714
738
}
715
739
716
740
function onReleaseOldSourceFile ( oldSourceFile : SourceFile , _oldOptions : CompilerOptions ) {
@@ -721,10 +745,10 @@ namespace ts {
721
745
// there was version update and new source file was created.
722
746
if ( hostSourceFileInfo ) {
723
747
// record the missing file paths so they can be removed later if watchers arent tracking them
724
- if ( isString ( hostSourceFileInfo ) ) {
748
+ if ( isFileMissingOnHost ( hostSourceFileInfo ) ) {
725
749
( missingFilePathsRequestedForRelease || ( missingFilePathsRequestedForRelease = [ ] ) ) . push ( oldSourceFile . path ) ;
726
750
}
727
- else if ( hostSourceFileInfo . sourceFile === oldSourceFile ) {
751
+ else if ( ( hostSourceFileInfo as FilePresentOnHost ) . sourceFile === oldSourceFile ) {
728
752
sourceFilesCache . delete ( oldSourceFile . path ) ;
729
753
resolutionCache . removeResolutionsOfFile ( oldSourceFile . path ) ;
730
754
}
@@ -808,27 +832,12 @@ namespace ts {
808
832
809
833
function onSourceFileChange ( fileName : string , eventKind : FileWatcherEventKind , path : Path ) {
810
834
updateCachedSystemWithFile ( fileName , path , eventKind ) ;
811
- const hostSourceFile = sourceFilesCache . get ( path ) ;
812
- if ( hostSourceFile ) {
813
- // Update the cache
814
- if ( eventKind === FileWatcherEventKind . Deleted ) {
815
- resolutionCache . invalidateResolutionOfFile ( path ) ;
816
- if ( ! isString ( hostSourceFile ) ) {
817
- hostSourceFile . fileWatcher . close ( ) ;
818
- sourceFilesCache . set ( path , ( ++ hostSourceFile . version ) . toString ( ) ) ;
819
- }
820
- }
821
- else {
822
- // Deleted file created
823
- if ( isString ( hostSourceFile ) ) {
824
- sourceFilesCache . delete ( path ) ;
825
- }
826
- else {
827
- // file changed - just update the version
828
- hostSourceFile . version ++ ;
829
- }
830
- }
835
+
836
+ // Update the source file cache
837
+ if ( eventKind === FileWatcherEventKind . Deleted && sourceFilesCache . get ( path ) ) {
838
+ resolutionCache . invalidateResolutionOfFile ( path ) ;
831
839
}
840
+ nextSourceFileVersion ( path ) ;
832
841
833
842
// Update the program
834
843
scheduleProgramUpdate ( ) ;
@@ -856,7 +865,7 @@ namespace ts {
856
865
missingFilesMap . delete ( missingFilePath ) ;
857
866
858
867
// Delete the entry in the source files cache so that new source file is created
859
- removeSourceFile ( missingFilePath ) ;
868
+ nextSourceFileVersion ( missingFilePath ) ;
860
869
861
870
// When a missing file is created, we should update the graph.
862
871
scheduleProgramUpdate ( ) ;
@@ -885,17 +894,10 @@ namespace ts {
885
894
const fileOrDirectoryPath = toPath ( fileOrDirectory ) ;
886
895
887
896
// Since the file existance changed, update the sourceFiles cache
888
- const result = cachedDirectoryStructureHost && cachedDirectoryStructureHost . addOrDeleteFileOrDirectory ( fileOrDirectory , fileOrDirectoryPath ) ;
889
-
890
- // Instead of deleting the file, mark it as changed instead
891
- // Many times node calls add/remove/file when watching directories recursively
892
- const hostSourceFile = sourceFilesCache . get ( fileOrDirectoryPath ) ;
893
- if ( hostSourceFile && ! isString ( hostSourceFile ) && ( result ? result . fileExists : directoryStructureHost . fileExists ( fileOrDirectory ) ) ) {
894
- hostSourceFile . version ++ ;
895
- }
896
- else {
897
- removeSourceFile ( fileOrDirectoryPath ) ;
897
+ if ( cachedDirectoryStructureHost ) {
898
+ cachedDirectoryStructureHost . addOrDeleteFileOrDirectory ( fileOrDirectory , fileOrDirectoryPath ) ;
898
899
}
900
+ nextSourceFileVersion ( fileOrDirectoryPath ) ;
899
901
900
902
// If the the added or created file or directory is not supported file name, ignore the file
901
903
// But when watched directory is added/removed, we need to reload the file list
0 commit comments