@@ -1346,14 +1346,52 @@ namespace ts {
13461346 }
13471347
13481348 function getUpToDateStatusWorker ( state : SolutionBuilderState , project : ParsedCommandLine , resolvedPath : ResolvedConfigFilePath ) : UpToDateStatus {
1349- // Container if no files are specified in the project
1350- if ( ! project . fileNames . length && ! canJsonReportNoInputFiles ( project . raw ) ) {
1349+ // Container if no files are specified in the project
1350+ if ( ! project . fileNames . length && ! canJsonReportNoInputFiles ( project . raw ) ) {
13511351 return {
13521352 type : UpToDateStatusType . ContainerOnly
13531353 } ;
13541354 }
13551355
1356+ // Fast check to see if reference projects are buildable
1357+ let referenceStatuses ;
13561358 const force = ! ! state . options . force ;
1359+ if ( project . projectReferences ) {
1360+ state . projectStatus . set ( resolvedPath , { type : UpToDateStatusType . ComputingUpstream } ) ;
1361+ for ( const ref of project . projectReferences ) {
1362+ const resolvedRef = resolveProjectReferencePath ( ref ) ;
1363+ const resolvedRefPath = toResolvedConfigFilePath ( state , resolvedRef ) ;
1364+ const refStatus = getUpToDateStatus ( state , parseConfigFile ( state , resolvedRef , resolvedRefPath ) , resolvedRefPath ) ;
1365+
1366+ // Its a circular reference ignore the status of this project
1367+ if ( refStatus . type === UpToDateStatusType . ComputingUpstream ||
1368+ refStatus . type === UpToDateStatusType . ContainerOnly ) { // Container only ignore this project
1369+ continue ;
1370+ }
1371+
1372+ // An upstream project is blocked
1373+ if ( refStatus . type === UpToDateStatusType . Unbuildable ||
1374+ refStatus . type === UpToDateStatusType . UpstreamBlocked ) {
1375+ return {
1376+ type : UpToDateStatusType . UpstreamBlocked ,
1377+ upstreamProjectName : ref . path ,
1378+ upstreamProjectBlocked : refStatus . type === UpToDateStatusType . UpstreamBlocked
1379+ } ;
1380+ }
1381+
1382+ // If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
1383+ if ( refStatus . type !== UpToDateStatusType . UpToDate ) {
1384+ return {
1385+ type : UpToDateStatusType . UpstreamOutOfDate ,
1386+ upstreamProjectName : ref . path
1387+ } ;
1388+ }
1389+
1390+ if ( ! force ) ( referenceStatuses ||= [ ] ) . push ( { ref, refStatus } ) ;
1391+ }
1392+ }
1393+
1394+ // Check output files
13571395 let newestInputFileName : string = undefined ! ;
13581396 let newestInputFileTime = minimumDate ;
13591397 const { host } = state ;
@@ -1381,17 +1419,16 @@ namespace ts {
13811419 // Now see if all outputs are newer than the newest input
13821420 let oldestOutputFileName = "(none)" ;
13831421 let oldestOutputFileTime = maximumDate ;
1384- let missingOutputFileName : string | undefined ;
13851422 let newestDeclarationFileContentChangedTime = minimumDate ;
1386- let isOutOfDateWithInputs = false ;
13871423 if ( ! force ) {
13881424 for ( const output of outputs ) {
13891425 // Output is missing; can stop checking
1390- // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
13911426 const outputTime = getModifiedTime ( host , output ) ;
13921427 if ( outputTime === missingFileModifiedTime ) {
1393- missingOutputFileName = output ;
1394- break ;
1428+ return {
1429+ type : UpToDateStatusType . OutputMissing ,
1430+ missingOutputFileName : output
1431+ } ;
13951432 }
13961433
13971434 if ( outputTime < oldestOutputFileTime ) {
@@ -1400,10 +1437,12 @@ namespace ts {
14001437 }
14011438
14021439 // If an output is older than the newest input, we can stop checking
1403- // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
14041440 if ( outputTime < newestInputFileTime ) {
1405- isOutOfDateWithInputs = true ;
1406- break ;
1441+ return {
1442+ type : UpToDateStatusType . OutOfDateWithSelf ,
1443+ outOfDateOutputFileName : oldestOutputFileName ,
1444+ newerInputFileName : newestInputFileName
1445+ } ;
14071446 }
14081447
14091448 // Keep track of when the most recent time a .d.ts file was changed.
@@ -1419,96 +1458,47 @@ namespace ts {
14191458 let pseudoUpToDate = false ;
14201459 let usesPrepend = false ;
14211460 let upstreamChangedProject : string | undefined ;
1422- if ( project . projectReferences ) {
1423- state . projectStatus . set ( resolvedPath , { type : UpToDateStatusType . ComputingUpstream } ) ;
1424- for ( const ref of project . projectReferences ) {
1461+ if ( referenceStatuses ) {
1462+ for ( const { ref, refStatus } of referenceStatuses ) {
14251463 usesPrepend = usesPrepend || ! ! ( ref . prepend ) ;
1426- const resolvedRef = resolveProjectReferencePath ( ref ) ;
1427- const resolvedRefPath = toResolvedConfigFilePath ( state , resolvedRef ) ;
1428- const refStatus = getUpToDateStatus ( state , parseConfigFile ( state , resolvedRef , resolvedRefPath ) , resolvedRefPath ) ;
1429-
1430- // Its a circular reference ignore the status of this project
1431- if ( refStatus . type === UpToDateStatusType . ComputingUpstream ||
1432- refStatus . type === UpToDateStatusType . ContainerOnly ) { // Container only ignore this project
1464+ // If the upstream project's newest file is older than our oldest output, we
1465+ // can't be out of date because of it
1466+ if ( refStatus . newestInputFileTime && refStatus . newestInputFileTime <= oldestOutputFileTime ) {
14331467 continue ;
14341468 }
14351469
1436- // An upstream project is blocked
1437- if ( refStatus . type === UpToDateStatusType . Unbuildable ||
1438- refStatus . type === UpToDateStatusType . UpstreamBlocked ) {
1439- return {
1440- type : UpToDateStatusType . UpstreamBlocked ,
1441- upstreamProjectName : ref . path ,
1442- upstreamProjectBlocked : refStatus . type === UpToDateStatusType . UpstreamBlocked
1443- } ;
1444- }
1445-
1446- // If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
1447- if ( refStatus . type !== UpToDateStatusType . UpToDate ) {
1448- return {
1449- type : UpToDateStatusType . UpstreamOutOfDate ,
1450- upstreamProjectName : ref . path
1451- } ;
1470+ // If the upstream project has only change .d.ts files, and we've built
1471+ // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
1472+ if ( refStatus . newestDeclarationFileContentChangedTime && refStatus . newestDeclarationFileContentChangedTime <= oldestOutputFileTime ) {
1473+ pseudoUpToDate = true ;
1474+ upstreamChangedProject = ref . path ;
1475+ continue ;
14521476 }
14531477
1454- // Check oldest output file name only if there is no missing output file name
1455- // (a check we will have skipped if this is a forced build)
1456- if ( ! force && ! missingOutputFileName ) {
1457- // If the upstream project's newest file is older than our oldest output, we
1458- // can't be out of date because of it
1459- if ( refStatus . newestInputFileTime && refStatus . newestInputFileTime <= oldestOutputFileTime ) {
1460- continue ;
1461- }
1462-
1463- // If the upstream project has only change .d.ts files, and we've built
1464- // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
1465- if ( refStatus . newestDeclarationFileContentChangedTime && refStatus . newestDeclarationFileContentChangedTime <= oldestOutputFileTime ) {
1466- pseudoUpToDate = true ;
1467- upstreamChangedProject = ref . path ;
1468- continue ;
1469- }
1470-
1471- // We have an output older than an upstream output - we are out of date
1472- Debug . assert ( oldestOutputFileName !== undefined , "Should have an oldest output filename here" ) ;
1473- return {
1474- type : UpToDateStatusType . OutOfDateWithUpstream ,
1475- outOfDateOutputFileName : oldestOutputFileName ,
1476- newerProjectName : ref . path
1477- } ;
1478- }
1478+ // We have an output older than an upstream output - we are out of date
1479+ Debug . assert ( oldestOutputFileName !== undefined , "Should have an oldest output filename here" ) ;
1480+ return {
1481+ type : UpToDateStatusType . OutOfDateWithUpstream ,
1482+ outOfDateOutputFileName : oldestOutputFileName ,
1483+ newerProjectName : ref . path
1484+ } ;
14791485 }
14801486 }
14811487
1482- if ( missingOutputFileName !== undefined ) {
1483- return {
1484- type : UpToDateStatusType . OutputMissing ,
1485- missingOutputFileName
1486- } ;
1487- }
1488+ // Check tsconfig time
1489+ const configStatus = checkConfigFileUpToDateStatus ( state , project . options . configFilePath ! , oldestOutputFileTime , oldestOutputFileName ) ;
1490+ if ( configStatus ) return configStatus ;
14881491
1489- if ( isOutOfDateWithInputs ) {
1490- return {
1491- type : UpToDateStatusType . OutOfDateWithSelf ,
1492- outOfDateOutputFileName : oldestOutputFileName ,
1493- newerInputFileName : newestInputFileName
1494- } ;
1495- }
1496- else {
1497- // Check tsconfig time
1498- const configStatus = checkConfigFileUpToDateStatus ( state , project . options . configFilePath ! , oldestOutputFileTime , oldestOutputFileName ) ;
1499- if ( configStatus ) return configStatus ;
1500-
1501- // Check extended config time
1502- const extendedConfigStatus = forEach ( project . options . configFile ! . extendedSourceFiles || emptyArray , configFile => checkConfigFileUpToDateStatus ( state , configFile , oldestOutputFileTime , oldestOutputFileName ) ) ;
1503- if ( extendedConfigStatus ) return extendedConfigStatus ;
1504-
1505- // Check package file time
1506- const dependentPackageFileStatus = forEach (
1507- state . lastCachedPackageJsonLookups . get ( resolvedPath ) || emptyArray ,
1508- ( [ path ] ) => checkConfigFileUpToDateStatus ( state , path , oldestOutputFileTime , oldestOutputFileName )
1509- ) ;
1510- if ( dependentPackageFileStatus ) return dependentPackageFileStatus ;
1511- }
1492+ // Check extended config time
1493+ const extendedConfigStatus = forEach ( project . options . configFile ! . extendedSourceFiles || emptyArray , configFile => checkConfigFileUpToDateStatus ( state , configFile , oldestOutputFileTime , oldestOutputFileName ) ) ;
1494+ if ( extendedConfigStatus ) return extendedConfigStatus ;
1495+
1496+ // Check package file time
1497+ const dependentPackageFileStatus = forEach (
1498+ state . lastCachedPackageJsonLookups . get ( resolvedPath ) || emptyArray ,
1499+ ( [ path ] ) => checkConfigFileUpToDateStatus ( state , path , oldestOutputFileTime , oldestOutputFileName )
1500+ ) ;
1501+ if ( dependentPackageFileStatus ) return dependentPackageFileStatus ;
15121502
15131503 if ( ! force && ! state . buildInfoChecked . has ( resolvedPath ) ) {
15141504 state . buildInfoChecked . set ( resolvedPath , true ) ;
0 commit comments