@@ -12,6 +12,7 @@ namespace ts.server {
1212
1313 const childProcess : {
1414 fork ( modulePath : string , args : string [ ] , options ?: { execArgv : string [ ] , env ?: MapLike < string > } ) : NodeChildProcess ;
15+ execFileSync ( file : string , args : string [ ] , options : { stdio : "ignore" , env : MapLike < string > } ) : string | Buffer ;
1516 } = require ( "child_process" ) ;
1617
1718 const os : {
@@ -59,7 +60,7 @@ namespace ts.server {
5960
6061 interface NodeChildProcess {
6162 send ( message : any , sendHandle ?: any ) : void ;
62- on ( message : "message" , f : ( m : any ) => void ) : void ;
63+ on ( message : "message" | "exit" , f : ( m : any ) => void ) : void ;
6364 kill ( ) : void ;
6465 pid : number ;
6566 }
@@ -576,7 +577,84 @@ namespace ts.server {
576577 }
577578 }
578579
580+ function extractWatchDirectoryCacheKey ( path : string , currentDriveKey : string ) {
581+ path = normalizeSlashes ( path ) ;
582+ if ( isUNCPath ( path ) ) {
583+ // UNC path: extract server name
584+ // //server/location
585+ // ^ <- from 0 to this position
586+ const firstSlash = path . indexOf ( directorySeparator , 2 ) ;
587+ return firstSlash !== - 1 ? path . substring ( 0 , firstSlash ) . toLowerCase ( ) : path ;
588+ }
589+ const rootLength = getRootLength ( path ) ;
590+ if ( rootLength === 0 ) {
591+ // relative path - assume file is on the current drive
592+ return currentDriveKey ;
593+ }
594+ if ( path . charCodeAt ( 1 ) === CharacterCodes . colon && path . charCodeAt ( 2 ) === CharacterCodes . slash ) {
595+ // rooted path that starts with c:/... - extract drive letter
596+ return path . charAt ( 0 ) . toLowerCase ( ) ;
597+ }
598+ if ( path . charCodeAt ( 0 ) === CharacterCodes . slash && path . charCodeAt ( 1 ) !== CharacterCodes . slash ) {
599+ // rooted path that starts with slash - /somename - use key for current drive
600+ return currentDriveKey ;
601+ }
602+ // do not cache any other cases
603+ return undefined ;
604+ }
605+
606+ function isUNCPath ( s : string ) : boolean {
607+ return s . length > 2 && s . charCodeAt ( 0 ) === CharacterCodes . slash && s . charCodeAt ( 1 ) === CharacterCodes . slash ;
608+ }
609+
579610 const sys = < ServerHost > ts . sys ;
611+ // use watchGuard process on Windows when node version is 4 or later
612+ const useWatchGuard = process . platform === "win32" && getNodeMajorVersion ( ) >= 4 ;
613+ if ( useWatchGuard ) {
614+ const currentDrive = extractWatchDirectoryCacheKey ( sys . resolvePath ( sys . getCurrentDirectory ( ) ) , /*currentDriveKey*/ undefined ) ;
615+ const statusCache = createMap < boolean > ( ) ;
616+ const originalWatchDirectory = sys . watchDirectory ;
617+ sys . watchDirectory = function ( path : string , callback : DirectoryWatcherCallback , recursive ?: boolean ) : FileWatcher {
618+ const cacheKey = extractWatchDirectoryCacheKey ( path , currentDrive ) ;
619+ let status = cacheKey && statusCache . get ( cacheKey ) ;
620+ if ( status === undefined ) {
621+ if ( logger . hasLevel ( LogLevel . verbose ) ) {
622+ logger . info ( `${ cacheKey } for path ${ path } not found in cache...` ) ;
623+ }
624+ try {
625+ const args = [ combinePaths ( __dirname , "watchGuard.js" ) , path ] ;
626+ if ( logger . hasLevel ( LogLevel . verbose ) ) {
627+ logger . info ( `Starting ${ process . execPath } with args ${ JSON . stringify ( args ) } ` ) ;
628+ }
629+ childProcess . execFileSync ( process . execPath , args , { stdio : "ignore" , env : { "ELECTRON_RUN_AS_NODE" : "1" } } ) ;
630+ status = true ;
631+ if ( logger . hasLevel ( LogLevel . verbose ) ) {
632+ logger . info ( `WatchGuard for path ${ path } returned: OK` ) ;
633+ }
634+ }
635+ catch ( e ) {
636+ status = false ;
637+ if ( logger . hasLevel ( LogLevel . verbose ) ) {
638+ logger . info ( `WatchGuard for path ${ path } returned: ${ e . message } ` ) ;
639+ }
640+ }
641+ if ( cacheKey ) {
642+ statusCache . set ( cacheKey , status ) ;
643+ }
644+ }
645+ else if ( logger . hasLevel ( LogLevel . verbose ) ) {
646+ logger . info ( `watchDirectory for ${ path } uses cached drive information.` ) ;
647+ }
648+ if ( status ) {
649+ // this drive is safe to use - call real 'watchDirectory'
650+ return originalWatchDirectory . call ( sys , path , callback , recursive ) ;
651+ }
652+ else {
653+ // this drive is unsafe - return no-op watcher
654+ return { close ( ) { } } ;
655+ }
656+ }
657+ }
580658
581659 // Override sys.write because fs.writeSync is not reliable on Node 4
582660 sys . write = ( s : string ) => writeMessage ( new Buffer ( s , "utf8" ) ) ;
0 commit comments