@@ -33,7 +33,7 @@ namespace ts {
3333 Deleted
3434 }
3535
36- export type FileWatcherCallback = ( fileName : string , eventKind : FileWatcherEventKind ) => void ;
36+ export type FileWatcherCallback = ( fileName : string , eventKind : FileWatcherEventKind , modifiedTime ?: Date ) => void ;
3737 export type DirectoryWatcherCallback = ( fileName : string ) => void ;
3838 /*@internal */
3939 export interface WatchedFile {
@@ -364,15 +364,15 @@ namespace ts {
364364 const watcher = fsWatch (
365365 dirName ,
366366 FileSystemEntryKind . Directory ,
367- ( _eventName : string , relativeFileName ) => {
367+ ( _eventName : string , relativeFileName , modifiedTime ) => {
368368 // When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
369369 if ( ! isString ( relativeFileName ) ) return ;
370370 const fileName = getNormalizedAbsolutePath ( relativeFileName , dirName ) ;
371371 // Some applications save a working file via rename operations
372372 const callbacks = fileName && fileWatcherCallbacks . get ( toCanonicalName ( fileName ) ) ;
373373 if ( callbacks ) {
374374 for ( const fileCallback of callbacks ) {
375- fileCallback ( fileName , FileWatcherEventKind . Changed ) ;
375+ fileCallback ( fileName , FileWatcherEventKind . Changed , modifiedTime ) ;
376376 }
377377 }
378378 } ,
@@ -446,9 +446,9 @@ namespace ts {
446446 cache . set ( path , {
447447 watcher : watchFile (
448448 fileName ,
449- ( fileName , eventKind ) => forEach (
449+ ( fileName , eventKind , modifiedTime ) => forEach (
450450 callbacksCache . get ( path ) ,
451- cb => cb ( fileName , eventKind )
451+ cb => cb ( fileName , eventKind , modifiedTime )
452452 ) ,
453453 pollingInterval ,
454454 options
@@ -480,7 +480,7 @@ namespace ts {
480480 const newTime = modifiedTime . getTime ( ) ;
481481 if ( oldTime !== newTime ) {
482482 watchedFile . mtime = modifiedTime ;
483- watchedFile . callback ( watchedFile . fileName , getFileWatcherEventKind ( oldTime , newTime ) ) ;
483+ watchedFile . callback ( watchedFile . fileName , getFileWatcherEventKind ( oldTime , newTime ) , modifiedTime ) ;
484484 return true ;
485485 }
486486
@@ -776,7 +776,7 @@ namespace ts {
776776 }
777777
778778 /*@internal */
779- export type FsWatchCallback = ( eventName : "rename" | "change" , relativeFileName : string | undefined ) => void ;
779+ export type FsWatchCallback = ( eventName : "rename" | "change" , relativeFileName : string | undefined , modifiedTime ?: Date ) => void ;
780780 /*@internal */
781781 export type FsWatch = ( fileOrDirectory : string , entryKind : FileSystemEntryKind , callback : FsWatchCallback , recursive : boolean , fallbackPollingInterval : PollingInterval , fallbackOptions : WatchOptions | undefined ) => FileWatcher ;
782782
@@ -788,21 +788,22 @@ namespace ts {
788788
789789 /*@internal */
790790 export function createFileWatcherCallback ( callback : FsWatchCallback ) : FileWatcherCallback {
791- return ( _fileName , eventKind ) => callback ( eventKind === FileWatcherEventKind . Changed ? "change" : "rename" , "" ) ;
791+ return ( _fileName , eventKind , modifiedTime ) => callback ( eventKind === FileWatcherEventKind . Changed ? "change" : "rename" , "" , modifiedTime ) ;
792792 }
793793
794794 function createFsWatchCallbackForFileWatcherCallback (
795795 fileName : string ,
796796 callback : FileWatcherCallback ,
797- fileExists : System [ "fileExists" ]
797+ getModifiedTime : NonNullable < System [ "getModifiedTime" ] >
798798 ) : FsWatchCallback {
799- return eventName => {
799+ return ( eventName , _relativeFileName , modifiedTime ) => {
800800 if ( eventName === "rename" ) {
801- callback ( fileName , fileExists ( fileName ) ? FileWatcherEventKind . Created : FileWatcherEventKind . Deleted ) ;
801+ modifiedTime ||= getModifiedTime ( fileName ) || missingFileModifiedTime ;
802+ callback ( fileName , modifiedTime !== missingFileModifiedTime ? FileWatcherEventKind . Created : FileWatcherEventKind . Deleted , modifiedTime ) ;
802803 }
803804 else {
804805 // Change
805- callback ( fileName , FileWatcherEventKind . Changed ) ;
806+ callback ( fileName , FileWatcherEventKind . Changed , modifiedTime ) ;
806807 }
807808 } ;
808809 }
@@ -850,7 +851,6 @@ namespace ts {
850851 clearTimeout : NonNullable < System [ "clearTimeout" ] > ;
851852 // For fs events :
852853 fsWatch : FsWatch ;
853- fileExists : System [ "fileExists" ] ;
854854 useCaseSensitiveFileNames : boolean ;
855855 getCurrentDirectory : System [ "getCurrentDirectory" ] ;
856856 fsSupportsRecursiveFsWatch : boolean ;
@@ -871,7 +871,6 @@ namespace ts {
871871 setTimeout,
872872 clearTimeout,
873873 fsWatch,
874- fileExists,
875874 useCaseSensitiveFileNames,
876875 getCurrentDirectory,
877876 fsSupportsRecursiveFsWatch,
@@ -908,7 +907,7 @@ namespace ts {
908907 return fsWatch (
909908 fileName ,
910909 FileSystemEntryKind . File ,
911- createFsWatchCallbackForFileWatcherCallback ( fileName , callback , fileExists ) ,
910+ createFsWatchCallbackForFileWatcherCallback ( fileName , callback , getModifiedTime ) ,
912911 /*recursive*/ false ,
913912 pollingInterval ,
914913 getFallbackOptions ( options )
@@ -1297,7 +1296,6 @@ namespace ts {
12971296 fsWatch,
12981297 useCaseSensitiveFileNames,
12991298 getCurrentDirectory,
1300- fileExists,
13011299 // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
13021300 // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
13031301 fsSupportsRecursiveFsWatch,
@@ -1542,7 +1540,7 @@ namespace ts {
15421540 close : ( ) => _fs . unwatchFile ( fileName , fileChanged )
15431541 } ;
15441542
1545- function fileChanged ( curr : any , prev : any ) {
1543+ function fileChanged ( curr : import ( "fs" ) . Stats , prev : import ( "fs" ) . Stats ) {
15461544 // previous event kind check is to ensure we recongnize the file as previously also missing when it is restored or renamed twice (that is it disappears and reappears)
15471545 // In such case, prevTime returned is same as prev time of event when file was deleted as per node documentation
15481546 const isPreviouslyDeleted = + prev . mtime === 0 || eventKind === FileWatcherEventKind . Deleted ;
@@ -1564,7 +1562,7 @@ namespace ts {
15641562 // File changed
15651563 eventKind = FileWatcherEventKind . Changed ;
15661564 }
1567- callback ( fileName , eventKind ) ;
1565+ callback ( fileName , eventKind , curr . mtime ) ;
15681566 }
15691567 }
15701568
@@ -1599,10 +1597,10 @@ namespace ts {
15991597 * Invoke the callback with rename and update the watcher if not closed
16001598 * @param createWatcher
16011599 */
1602- function invokeCallbackAndUpdateWatcher ( createWatcher : ( ) => FileWatcher ) {
1600+ function invokeCallbackAndUpdateWatcher ( createWatcher : ( ) => FileWatcher , modifiedTime ?: Date ) {
16031601 sysLog ( `sysLog:: ${ fileOrDirectory } :: Changing watcher to ${ createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing" } FileSystemEntryWatcher` ) ;
16041602 // Call the callback for current directory
1605- callback ( "rename" , "" ) ;
1603+ callback ( "rename" , "" , modifiedTime ) ;
16061604
16071605 // If watcher is not closed, update it
16081606 if ( watcher ) {
@@ -1656,13 +1654,14 @@ namespace ts {
16561654 function callbackChangingToMissingFileSystemEntry ( event : "rename" | "change" , relativeName : string | undefined ) {
16571655 // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations
16581656 // Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path
1657+ const modifiedTime = getModifiedTime ( fileOrDirectory ) || missingFileModifiedTime ;
16591658 return event === "rename" &&
16601659 ( ! relativeName ||
16611660 relativeName === lastDirectoryPart ||
16621661 ( relativeName . lastIndexOf ( lastDirectoryPartWithDirectorySeparator ! ) !== - 1 && relativeName . lastIndexOf ( lastDirectoryPartWithDirectorySeparator ! ) === relativeName . length - lastDirectoryPartWithDirectorySeparator ! . length ) ) &&
1663- ! fileSystemEntryExists ( fileOrDirectory , entryKind ) ?
1664- invokeCallbackAndUpdateWatcher ( watchMissingFileSystemEntry ) :
1665- callback ( event , relativeName ) ;
1662+ modifiedTime === missingFileModifiedTime ?
1663+ invokeCallbackAndUpdateWatcher ( watchMissingFileSystemEntry , modifiedTime ) :
1664+ callback ( event , relativeName , modifiedTime ) ;
16661665 }
16671666
16681667 /**
@@ -1685,12 +1684,15 @@ namespace ts {
16851684 function watchMissingFileSystemEntry ( ) : FileWatcher {
16861685 return watchFile (
16871686 fileOrDirectory ,
1688- ( _fileName , eventKind ) => {
1689- if ( eventKind === FileWatcherEventKind . Created && fileSystemEntryExists ( fileOrDirectory , entryKind ) ) {
1690- // Call the callback for current file or directory
1691- // For now it could be callback for the inner directory creation,
1692- // but just return current directory, better than current no-op
1693- invokeCallbackAndUpdateWatcher ( watchPresentFileSystemEntry ) ;
1687+ ( _fileName , eventKind , modifiedTime ) => {
1688+ if ( eventKind === FileWatcherEventKind . Created ) {
1689+ modifiedTime ||= getModifiedTime ( fileOrDirectory ) || missingFileModifiedTime ;
1690+ if ( modifiedTime !== missingFileModifiedTime ) {
1691+ // Call the callback for current file or directory
1692+ // For now it could be callback for the inner directory creation,
1693+ // but just return current directory, better than current no-op
1694+ invokeCallbackAndUpdateWatcher ( watchPresentFileSystemEntry , modifiedTime ) ;
1695+ }
16941696 }
16951697 } ,
16961698 fallbackPollingInterval ,
0 commit comments