@@ -245,6 +245,7 @@ namespace ts {
245
245
readonly projectStatus : ESMap < ResolvedConfigFilePath , UpToDateStatus > ;
246
246
readonly extendedConfigCache : ESMap < string , ExtendedConfigCacheEntry > ;
247
247
readonly buildInfoCache : ESMap < ResolvedConfigFilePath , BuildInfoCacheEntry > ;
248
+ readonly outputTimeStamps : ESMap < ResolvedConfigFilePath , ESMap < Path , Date > > ;
248
249
249
250
readonly builderPrograms : ESMap < ResolvedConfigFilePath , T > ;
250
251
readonly diagnostics : ESMap < ResolvedConfigFilePath , readonly Diagnostic [ ] > ;
@@ -330,6 +331,7 @@ namespace ts {
330
331
projectStatus : new Map ( ) ,
331
332
extendedConfigCache : new Map ( ) ,
332
333
buildInfoCache : new Map ( ) ,
334
+ outputTimeStamps : new Map ( ) ,
333
335
334
336
builderPrograms : new Map ( ) ,
335
337
diagnostics : new Map ( ) ,
@@ -493,6 +495,7 @@ namespace ts {
493
495
mutateMapSkippingNewValues ( state . projectPendingBuild , currentProjects , noopOnDelete ) ;
494
496
mutateMapSkippingNewValues ( state . projectErrorsReported , currentProjects , noopOnDelete ) ;
495
497
mutateMapSkippingNewValues ( state . buildInfoCache , currentProjects , noopOnDelete ) ;
498
+ mutateMapSkippingNewValues ( state . outputTimeStamps , currentProjects , noopOnDelete ) ;
496
499
497
500
// Remove watches for the program no longer in the solution
498
501
if ( state . watch ) {
@@ -983,15 +986,23 @@ namespace ts {
983
986
const existingBuildInfo = state . buildInfoCache . get ( projectPath ) ?. buildInfo || undefined ;
984
987
const emitterDiagnostics = createDiagnosticCollection ( ) ;
985
988
const emittedOutputs = new Map < Path , string > ( ) ;
989
+ const options = program . getCompilerOptions ( ) ;
990
+ const isIncremental = isIncrementalCompilation ( options ) ;
991
+ let outputTimeStampMap : ESMap < Path , Date > | undefined ;
992
+ let now : Date | undefined ;
986
993
outputFiles . forEach ( ( { name, text, writeByteOrderMark, buildInfo } ) => {
994
+ const path = toPath ( state , name ) ;
987
995
emittedOutputs . set ( toPath ( state , name ) , name ) ;
988
996
if ( buildInfo ) {
989
- setBuildInfo ( state , buildInfo , projectPath , program ! . getCompilerOptions ( ) ) ;
997
+ setBuildInfo ( state , buildInfo , projectPath , options ) ;
990
998
if ( buildInfo . program ?. dtsChangeTime !== existingBuildInfo ?. program ?. dtsChangeTime ) {
991
999
resultFlags &= ~ BuildResultFlags . DeclarationOutputUnchanged ;
992
1000
}
993
1001
}
994
1002
writeFile ( writeFileCallback ? { writeFile : writeFileCallback } : compilerHost , emitterDiagnostics , name , text , writeByteOrderMark ) ;
1003
+ if ( ! isIncremental ) {
1004
+ ( outputTimeStampMap ||= getOutputTimeStampMap ( state , projectPath ) ) . set ( path , now ||= getCurrentTime ( state . host ) ) ;
1005
+ }
995
1006
} ) ;
996
1007
997
1008
finishEmit (
@@ -1050,7 +1061,7 @@ namespace ts {
1050
1061
}
1051
1062
1052
1063
// Update time stamps for rest of the outputs
1053
- updateOutputTimestampsWorker ( state , config , Diagnostics . Updating_unchanged_output_timestamps_of_project_0 , emittedOutputs ) ;
1064
+ updateOutputTimestampsWorker ( state , config , projectPath , Diagnostics . Updating_unchanged_output_timestamps_of_project_0 , emittedOutputs ) ;
1054
1065
state . diagnostics . delete ( projectPath ) ;
1055
1066
state . projectStatus . set ( projectPath , {
1056
1067
type : UpToDateStatusType . UpToDate ,
@@ -1402,6 +1413,12 @@ namespace ts {
1402
1413
} ;
1403
1414
}
1404
1415
1416
+ function getOutputTimeStampMap ( state : SolutionBuilderState , resolvedConfigFilePath : ResolvedConfigFilePath ) {
1417
+ let result = state . outputTimeStamps . get ( resolvedConfigFilePath ) ;
1418
+ if ( ! result ) state . outputTimeStamps . set ( resolvedConfigFilePath , result = new Map ( ) ) ;
1419
+ return result ;
1420
+ }
1421
+
1405
1422
function setBuildInfo ( state : SolutionBuilderState , buildInfo : BuildInfo , resolvedConfigPath : ResolvedConfigFilePath , options : CompilerOptions ) {
1406
1423
const buildInfoPath = getTsBuildInfoEmitOutputFilePath ( options ) ! ;
1407
1424
const existing = getBuildInfoCacheEntry ( state , buildInfoPath , resolvedConfigPath ) ;
@@ -1573,9 +1590,12 @@ namespace ts {
1573
1590
if ( ! buildInfoPath ) {
1574
1591
// Collect the expected outputs of this project
1575
1592
const outputs = getAllProjectOutputs ( project , ! host . useCaseSensitiveFileNames ( ) ) ;
1593
+ const outputTimeStampMap = getOutputTimeStampMap ( state , resolvedPath ) ;
1576
1594
for ( const output of outputs ) {
1595
+ const path = toPath ( state , output ) ;
1577
1596
// Output is missing; can stop checking
1578
- const outputTime = ts . getModifiedTime ( state . host , output ) ;
1597
+ let outputTime = outputTimeStampMap . get ( path ) ;
1598
+ if ( ! outputTime ) outputTimeStampMap . set ( path , outputTime = ts . getModifiedTime ( state . host , output ) ) ;
1579
1599
if ( outputTime === missingFileModifiedTime ) {
1580
1600
return {
1581
1601
type : UpToDateStatusType . OutputMissing ,
@@ -1711,37 +1731,46 @@ namespace ts {
1711
1731
function updateOutputTimestampsWorker (
1712
1732
state : SolutionBuilderState ,
1713
1733
proj : ParsedCommandLine ,
1734
+ projectPath : ResolvedConfigFilePath ,
1714
1735
verboseMessage : DiagnosticMessage ,
1715
1736
skipOutputs ?: ESMap < Path , string >
1716
1737
) {
1717
1738
if ( proj . options . noEmit ) return ;
1739
+ let now : Date | undefined ;
1718
1740
const buildInfoPath = getTsBuildInfoEmitOutputFilePath ( proj . options ) ;
1719
1741
if ( buildInfoPath ) {
1720
1742
if ( ! skipOutputs ?. has ( toPath ( state , buildInfoPath ) ) ) {
1721
1743
if ( ! ! state . options . verbose ) reportStatus ( state , verboseMessage , proj . options . configFilePath ! ) ;
1722
- state . host . setModifiedTime ( buildInfoPath , getCurrentTime ( state . host ) ) ;
1744
+ state . host . setModifiedTime ( buildInfoPath , now = getCurrentTime ( state . host ) ) ;
1745
+ getBuildInfoCacheEntry ( state , buildInfoPath , projectPath ) ! . modifiedTime = now ;
1723
1746
}
1747
+ state . outputTimeStamps . delete ( projectPath ) ;
1724
1748
return ;
1725
1749
}
1726
1750
1727
1751
const { host } = state ;
1728
1752
const outputs = getAllProjectOutputs ( proj , ! host . useCaseSensitiveFileNames ( ) ) ;
1753
+ const outputTimeStampMap = getOutputTimeStampMap ( state , projectPath ) ;
1754
+ const modifiedOutputs = new Set < Path > ( ) ;
1729
1755
if ( ! skipOutputs || outputs . length !== skipOutputs . size ) {
1730
1756
let reportVerbose = ! ! state . options . verbose ;
1731
- let now : Date | undefined ;
1732
1757
for ( const file of outputs ) {
1733
- if ( skipOutputs && skipOutputs . has ( toPath ( state , file ) ) ) {
1734
- continue ;
1735
- }
1736
-
1758
+ const path = toPath ( state , file ) ;
1759
+ if ( skipOutputs ?. has ( path ) ) continue ;
1737
1760
if ( reportVerbose ) {
1738
1761
reportVerbose = false ;
1739
1762
reportStatus ( state , verboseMessage , proj . options . configFilePath ! ) ;
1740
1763
}
1741
-
1742
1764
host . setModifiedTime ( file , now ||= getCurrentTime ( state . host ) ) ;
1765
+ outputTimeStampMap . set ( path , now ) ;
1766
+ modifiedOutputs . add ( path ) ;
1743
1767
}
1744
1768
}
1769
+
1770
+ // Clear out timestamps not in output list any more
1771
+ outputTimeStampMap . forEach ( ( _value , key ) => {
1772
+ if ( ! skipOutputs ?. has ( key ) && ! modifiedOutputs . has ( key ) ) outputTimeStampMap . delete ( key ) ;
1773
+ } ) ;
1745
1774
}
1746
1775
1747
1776
function getDtsChangeTime ( state : SolutionBuilderState , options : CompilerOptions , resolvedConfigPath : ResolvedConfigFilePath ) {
@@ -1755,7 +1784,7 @@ namespace ts {
1755
1784
if ( state . options . dry ) {
1756
1785
return reportStatus ( state , Diagnostics . A_non_dry_build_would_update_timestamps_for_output_of_project_0 , proj . options . configFilePath ! ) ;
1757
1786
}
1758
- updateOutputTimestampsWorker ( state , proj , Diagnostics . Updating_output_timestamps_of_project_0 ) ;
1787
+ updateOutputTimestampsWorker ( state , proj , resolvedPath , Diagnostics . Updating_output_timestamps_of_project_0 ) ;
1759
1788
state . projectStatus . set ( resolvedPath , {
1760
1789
type : UpToDateStatusType . UpToDate ,
1761
1790
newestDeclarationFileContentChangedTime : getDtsChangeTime ( state , proj . options , resolvedPath ) ,
0 commit comments