@@ -64,8 +64,8 @@ namespace ts {
64
64
return existingValue || newValue ! ;
65
65
}
66
66
67
- function getOrCreateValueMapFromConfigFileMap < T > ( configFileMap : ESMap < ResolvedConfigFilePath , ESMap < string , T > > , resolved : ResolvedConfigFilePath ) : ESMap < string , T > {
68
- return getOrCreateValueFromConfigFileMap < ESMap < string , T > > ( configFileMap , resolved , ( ) => new Map ( ) ) ;
67
+ function getOrCreateValueMapFromConfigFileMap < K extends string , V > ( configFileMap : ESMap < ResolvedConfigFilePath , ESMap < K , V > > , resolved : ResolvedConfigFilePath ) : ESMap < K , V > {
68
+ return getOrCreateValueFromConfigFileMap ( configFileMap , resolved , ( ) => new Map ( ) ) ;
69
69
}
70
70
71
71
function newer ( date1 : Date | undefined , date2 : Date ) : Date | undefined {
@@ -212,6 +212,12 @@ namespace ts {
212
212
originalGetSourceFile : CompilerHost [ "getSourceFile" ] ;
213
213
}
214
214
215
+ interface FileWatcherWithModifiedTime {
216
+ callbacks : FileWatcherCallback [ ] ;
217
+ watcher : FileWatcher ;
218
+ modifiedTime : Date | undefined ;
219
+ }
220
+
215
221
interface SolutionBuilderState < T extends BuilderProgram = BuilderProgram > extends WatchFactory < WatchType , ResolvedConfigFileName > {
216
222
readonly host : SolutionBuilderHost < T > ;
217
223
readonly hostWithWatch : SolutionBuilderWithWatchHost < T > ;
@@ -259,6 +265,8 @@ namespace ts {
259
265
readonly allWatchedConfigFiles : ESMap < ResolvedConfigFilePath , FileWatcher > ;
260
266
readonly allWatchedExtendedConfigFiles : ESMap < Path , SharedExtendedConfigFileWatcher < ResolvedConfigFilePath > > ;
261
267
readonly allWatchedPackageJsonFiles : ESMap < ResolvedConfigFilePath , ESMap < Path , FileWatcher > > ;
268
+ readonly filesWatched : ESMap < Path , FileWatcherWithModifiedTime | Date > ;
269
+
262
270
readonly lastCachedPackageJsonLookups : ESMap < ResolvedConfigFilePath , readonly ( readonly [ Path , object | boolean ] ) [ ] | undefined > ;
263
271
264
272
timerToBuildInvalidatedProject : any ;
@@ -341,6 +349,8 @@ namespace ts {
341
349
allWatchedConfigFiles : new Map ( ) ,
342
350
allWatchedExtendedConfigFiles : new Map ( ) ,
343
351
allWatchedPackageJsonFiles : new Map ( ) ,
352
+ filesWatched : new Map ( ) ,
353
+
344
354
lastCachedPackageJsonLookups : new Map ( ) ,
345
355
346
356
timerToBuildInvalidatedProject : undefined ,
@@ -969,7 +979,7 @@ namespace ts {
969
979
if ( resultFlags === BuildResultFlags . DeclarationOutputUnchanged && isDeclarationFileName ( name ) ) {
970
980
// Check for unchanged .d.ts files
971
981
if ( state . readFileWithCache ( name ) === text ) {
972
- newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , getModifiedTime ( host , name ) ) ;
982
+ newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , ts . getModifiedTime ( host , name ) ) ;
973
983
}
974
984
else {
975
985
resultFlags &= ~ BuildResultFlags . DeclarationOutputUnchanged ;
@@ -1323,9 +1333,66 @@ namespace ts {
1323
1333
return { buildResult, step : BuildStep . QueueReferencingProjects } ;
1324
1334
}
1325
1335
1336
+ function isFileWatcherWithModifiedTime ( value : FileWatcherWithModifiedTime | Date ) : value is FileWatcherWithModifiedTime {
1337
+ return ! ! ( value as FileWatcherWithModifiedTime ) . watcher ;
1338
+ }
1339
+
1340
+ function getModifiedTime ( state : SolutionBuilderState , fileName : string ) : Date {
1341
+ const path = toPath ( state , fileName ) ;
1342
+ const existing = state . filesWatched . get ( path ) ;
1343
+ if ( state . watch && ! ! existing ) {
1344
+ if ( ! isFileWatcherWithModifiedTime ( existing ) ) return existing ;
1345
+ if ( existing . modifiedTime ) return existing . modifiedTime ;
1346
+ }
1347
+ const result = ts . getModifiedTime ( state . host , fileName ) ;
1348
+ if ( state . watch ) {
1349
+ if ( existing ) ( existing as FileWatcherWithModifiedTime ) . modifiedTime = result ;
1350
+ else state . filesWatched . set ( path , result ) ;
1351
+ }
1352
+ return result ;
1353
+ }
1354
+
1355
+ function watchFile ( state : SolutionBuilderState , file : string , callback : FileWatcherCallback , pollingInterval : PollingInterval , options : WatchOptions | undefined , watchType : WatchType , project ?: ResolvedConfigFileName ) : FileWatcher {
1356
+ const path = toPath ( state , file ) ;
1357
+ const existing = state . filesWatched . get ( path ) ;
1358
+ if ( existing && isFileWatcherWithModifiedTime ( existing ) ) {
1359
+ existing . callbacks . push ( callback ) ;
1360
+ }
1361
+ else {
1362
+ const watcher = state . watchFile (
1363
+ file ,
1364
+ ( fileName , eventKind , modifiedTime ) => {
1365
+ const existing = Debug . checkDefined ( state . filesWatched . get ( path ) ) ;
1366
+ Debug . assert ( isFileWatcherWithModifiedTime ( existing ) ) ;
1367
+ existing . modifiedTime = modifiedTime ;
1368
+ existing . callbacks . forEach ( cb => cb ( fileName , eventKind , modifiedTime ) ) ;
1369
+ } ,
1370
+ pollingInterval ,
1371
+ options ,
1372
+ watchType ,
1373
+ project
1374
+ ) ;
1375
+ state . filesWatched . set ( path , { callbacks : [ callback ] , watcher, modifiedTime : existing } ) ;
1376
+ }
1377
+
1378
+ return {
1379
+ close : ( ) => {
1380
+ const existing = Debug . checkDefined ( state . filesWatched . get ( path ) ) ;
1381
+ Debug . assert ( isFileWatcherWithModifiedTime ( existing ) ) ;
1382
+ if ( existing . callbacks . length === 1 ) {
1383
+ state . filesWatched . delete ( path ) ;
1384
+ closeFileWatcherOf ( existing ) ;
1385
+ }
1386
+ else {
1387
+ unorderedRemoveItem ( existing . callbacks , callback ) ;
1388
+ }
1389
+ }
1390
+ } ;
1391
+ }
1392
+
1326
1393
function checkConfigFileUpToDateStatus ( state : SolutionBuilderState , configFile : string , oldestOutputFileTime : Date , oldestOutputFileName : string ) : Status . OutOfDateWithSelf | undefined {
1327
1394
// Check tsconfig time
1328
- const tsconfigTime = getModifiedTime ( state . host , configFile ) ;
1395
+ const tsconfigTime = getModifiedTime ( state , configFile ) ;
1329
1396
if ( oldestOutputFileTime < tsconfigTime ) {
1330
1397
return {
1331
1398
type : UpToDateStatusType . OutOfDateWithSelf ,
@@ -1387,7 +1454,7 @@ namespace ts {
1387
1454
const { host } = state ;
1388
1455
// Get timestamps of input files
1389
1456
for ( const inputFile of project . fileNames ) {
1390
- const inputTime = getModifiedTime ( host , inputFile ) ;
1457
+ const inputTime = getModifiedTime ( state , inputFile ) ;
1391
1458
if ( inputTime === missingFileModifiedTime ) {
1392
1459
return {
1393
1460
type : UpToDateStatusType . Unbuildable ,
@@ -1413,7 +1480,7 @@ namespace ts {
1413
1480
if ( ! force ) {
1414
1481
for ( const output of outputs ) {
1415
1482
// Output is missing; can stop checking
1416
- const outputTime = getModifiedTime ( host , output ) ;
1483
+ const outputTime = ts . getModifiedTime ( host , output ) ;
1417
1484
if ( outputTime === missingFileModifiedTime ) {
1418
1485
return {
1419
1486
type : UpToDateStatusType . OutputMissing ,
@@ -1556,7 +1623,7 @@ namespace ts {
1556
1623
}
1557
1624
1558
1625
if ( ! anyDtsChange && isDeclarationFileName ( file ) ) {
1559
- newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , getModifiedTime ( host , file ) ) ;
1626
+ newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , ts . getModifiedTime ( host , file ) ) ;
1560
1627
}
1561
1628
1562
1629
host . setModifiedTime ( file , now ) ;
@@ -1778,11 +1845,10 @@ namespace ts {
1778
1845
1779
1846
function watchConfigFile ( state : SolutionBuilderState , resolved : ResolvedConfigFileName , resolvedPath : ResolvedConfigFilePath , parsed : ParsedCommandLine | undefined ) {
1780
1847
if ( ! state . watch || state . allWatchedConfigFiles . has ( resolvedPath ) ) return ;
1781
- state . allWatchedConfigFiles . set ( resolvedPath , state . watchFile (
1848
+ state . allWatchedConfigFiles . set ( resolvedPath , watchFile (
1849
+ state ,
1782
1850
resolved ,
1783
- ( ) => {
1784
- invalidateProjectAndScheduleBuilds ( state , resolvedPath , ConfigFileProgramReloadLevel . Full ) ;
1785
- } ,
1851
+ ( ) => invalidateProjectAndScheduleBuilds ( state , resolvedPath , ConfigFileProgramReloadLevel . Full ) ,
1786
1852
PollingInterval . High ,
1787
1853
parsed ?. watchOptions ,
1788
1854
WatchType . ConfigFile ,
@@ -1795,11 +1861,11 @@ namespace ts {
1795
1861
resolvedPath ,
1796
1862
parsed ?. options ,
1797
1863
state . allWatchedExtendedConfigFiles ,
1798
- ( extendedConfigFileName , extendedConfigFilePath ) => state . watchFile (
1864
+ ( extendedConfigFileName , extendedConfigFilePath ) => watchFile (
1865
+ state ,
1799
1866
extendedConfigFileName ,
1800
1867
( ) => state . allWatchedExtendedConfigFiles . get ( extendedConfigFilePath ) ?. projects . forEach ( projectConfigFilePath =>
1801
- invalidateProjectAndScheduleBuilds ( state , projectConfigFilePath , ConfigFileProgramReloadLevel . Full )
1802
- ) ,
1868
+ invalidateProjectAndScheduleBuilds ( state , projectConfigFilePath , ConfigFileProgramReloadLevel . Full ) ) ,
1803
1869
PollingInterval . High ,
1804
1870
parsed ?. watchOptions ,
1805
1871
WatchType . ExtendedConfigFile ,
@@ -1845,7 +1911,8 @@ namespace ts {
1845
1911
getOrCreateValueMapFromConfigFileMap ( state . allWatchedInputFiles , resolvedPath ) ,
1846
1912
arrayToMap ( parsed . fileNames , fileName => toPath ( state , fileName ) ) ,
1847
1913
{
1848
- createNewValue : ( _path , input ) => state . watchFile (
1914
+ createNewValue : ( _path , input ) => watchFile (
1915
+ state ,
1849
1916
input ,
1850
1917
( ) => invalidateProjectAndScheduleBuilds ( state , resolvedPath , ConfigFileProgramReloadLevel . None ) ,
1851
1918
PollingInterval . Low ,
@@ -1864,7 +1931,8 @@ namespace ts {
1864
1931
getOrCreateValueMapFromConfigFileMap ( state . allWatchedPackageJsonFiles , resolvedPath ) ,
1865
1932
new Map ( state . lastCachedPackageJsonLookups . get ( resolvedPath ) ) ,
1866
1933
{
1867
- createNewValue : ( path , _input ) => state . watchFile (
1934
+ createNewValue : ( path , _input ) => watchFile (
1935
+ state ,
1868
1936
path ,
1869
1937
( ) => invalidateProjectAndScheduleBuilds ( state , resolvedPath , ConfigFileProgramReloadLevel . Full ) ,
1870
1938
PollingInterval . High ,
0 commit comments