@@ -69,7 +69,8 @@ namespace ts {
6969 OutputMissing ,
7070 OutOfDateWithSelf ,
7171 OutOfDateWithUpstream ,
72- UpstreamOutOfDate
72+ UpstreamOutOfDate ,
73+ UpstreamBlocked
7374 }
7475
7576 type UpToDateStatus =
@@ -78,7 +79,8 @@ namespace ts {
7879 | StatusOutputMissing
7980 | StatusOutOfDateWithSelf
8081 | StatusOutOfDateWithUpstream
81- | StatusUpstreamOutOfDate ;
82+ | StatusUpstreamOutOfDate
83+ | StatusUpstreamBlocked ;
8284
8385 /**
8486 * The project can't be built at all in its current state. For example,
@@ -128,6 +130,14 @@ namespace ts {
128130 upstreamProjectName : string ;
129131 }
130132
133+ /**
134+ * This project depends an upstream project with build errors
135+ */
136+ interface StatusUpstreamBlocked {
137+ type : UpToDateStatusType . UpstreamBlocked ;
138+ upstreamProjectName : string ;
139+ }
140+
131141 /**
132142 * One or more of the project's outputs is older than the newest output of
133143 * an upstream project.
@@ -466,33 +476,33 @@ namespace ts {
466476 const outputs = getAllProjectOutputs ( project ) ;
467477
468478 // Now see if all outputs are newer than the newest input
469- let oldestOutputFileName : string = undefined ! ;
479+ let oldestOutputFileName : string | undefined ;
470480 let oldestOutputFileTime : Date = maximumDate ;
471481 let newestOutputFileTime : Date = minimumDate ;
472482 let newestDeclarationFileContentChangedTime : Date = minimumDate ;
483+ let missingOutputFileName : string | undefined ;
484+ let isOutOfDateWithInputs = false ;
473485 for ( const output of outputs ) {
474- // Output is missing
486+ // Output is missing; can stop checking
487+ // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
475488 if ( ! host . fileExists ( output ) ) {
476- return {
477- type : UpToDateStatusType . OutputMissing ,
478- missingOutputFileName : output
479- } ;
489+ missingOutputFileName = output ;
490+ break ;
480491 }
481492
482493 const outputTime = host . getModifiedTime ! ( output ) ;
483- // If an output is older than the newest input, we can stop checking
484- if ( outputTime < newestInputFileTime ) {
485- return {
486- type : UpToDateStatusType . OutOfDateWithSelf ,
487- outOfDateOutputFileName : output ,
488- newerInputFileName : newestInputFileName
489- } ;
490- }
491-
492494 if ( outputTime < oldestOutputFileTime ) {
493495 oldestOutputFileTime = outputTime ;
494496 oldestOutputFileName = output ;
495497 }
498+
499+ // If an output is older than the newest input, we can stop checking
500+ // Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
501+ if ( outputTime < newestInputFileTime ) {
502+ isOutOfDateWithInputs = true ;
503+ break ;
504+ }
505+
496506 newestOutputFileTime = newer ( newestOutputFileTime , outputTime ) ;
497507
498508 // Keep track of when the most recent time a .d.ts file was changed.
@@ -511,13 +521,19 @@ namespace ts {
511521 }
512522
513523 let pseudoUpToDate = false ;
514- // By here, we know the project is at least up-to-date with its own inputs.
515- // See if any of its upstream projects are newer than it
516524 if ( project . projectReferences ) {
517525 for ( const ref of project . projectReferences ) {
518526 const resolvedRef = resolveProjectReferencePath ( host , ref ) as ResolvedConfigFileName ;
519527 const refStatus = getUpToDateStatus ( configFileCache . parseConfigFile ( resolvedRef ) ) ;
520528
529+ // An upstream project is blocked
530+ if ( refStatus . type === UpToDateStatusType . Unbuildable ) {
531+ return {
532+ type : UpToDateStatusType . UpstreamBlocked ,
533+ upstreamProjectName : ref . path
534+ } ;
535+ }
536+
521537 // If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
522538 if ( refStatus . type !== UpToDateStatusType . UpToDate ) {
523539 return {
@@ -543,12 +559,27 @@ namespace ts {
543559 Debug . assert ( oldestOutputFileName !== undefined , "Should have an oldest output filename here" ) ;
544560 return {
545561 type : UpToDateStatusType . OutOfDateWithUpstream ,
546- outOfDateOutputFileName : oldestOutputFileName ,
562+ outOfDateOutputFileName : oldestOutputFileName ! ,
547563 newerProjectName : ref . path
548564 } ;
549565 }
550566 }
551567
568+ if ( missingOutputFileName !== undefined ) {
569+ return {
570+ type : UpToDateStatusType . OutputMissing ,
571+ missingOutputFileName
572+ } ;
573+ }
574+
575+ if ( isOutOfDateWithInputs ) {
576+ return {
577+ type : UpToDateStatusType . OutOfDateWithSelf ,
578+ outOfDateOutputFileName : oldestOutputFileName ! ,
579+ newerInputFileName : newestInputFileName
580+ } ;
581+ }
582+
552583 // Up to date
553584 return {
554585 type : pseudoUpToDate ? UpToDateStatusType . UpToDateWithUpstreamTypes : UpToDateStatusType . UpToDate ,
@@ -637,6 +668,7 @@ namespace ts {
637668 if ( ! configFile ) {
638669 // Failed to read the config file
639670 resultFlags |= BuildResultFlags . ConfigFileErrors ;
671+ context . projectStatus . setValue ( proj , { type : UpToDateStatusType . Unbuildable , reason : "Config file errors" } ) ;
640672 return resultFlags ;
641673 }
642674
@@ -660,6 +692,7 @@ namespace ts {
660692 for ( const diag of syntaxDiagnostics ) {
661693 reportDiagnostic ( diag ) ;
662694 }
695+ context . projectStatus . setValue ( proj , { type : UpToDateStatusType . Unbuildable , reason : "Syntactic errors" } ) ;
663696 return resultFlags ;
664697 }
665698
@@ -671,6 +704,7 @@ namespace ts {
671704 for ( const diag of declDiagnostics ) {
672705 reportDiagnostic ( diag ) ;
673706 }
707+ context . projectStatus . setValue ( proj , { type : UpToDateStatusType . Unbuildable , reason : "Declaration file errors" } ) ;
674708 return resultFlags ;
675709 }
676710 }
@@ -681,6 +715,7 @@ namespace ts {
681715 for ( const diag of semanticDiagnostics ) {
682716 reportDiagnostic ( diag ) ;
683717 }
718+ context . projectStatus . setValue ( proj , { type : UpToDateStatusType . Unbuildable , reason : "Semantic errors" } ) ;
684719 return resultFlags ;
685720 }
686721
@@ -704,7 +739,6 @@ namespace ts {
704739 } ) ;
705740
706741 context . projectStatus . setValue ( proj , { type : UpToDateStatusType . UpToDate , newestDeclarationFileContentChangedTime } as UpToDateStatus ) ;
707-
708742 return resultFlags ;
709743 }
710744
@@ -812,15 +846,15 @@ namespace ts {
812846 if ( proj === undefined ) {
813847 break ;
814848 }
815-
816849 const status = getUpToDateStatus ( proj ) ;
817850 reportProjectStatus ( next , status ) ;
818851
852+ const projName = proj . options . configFilePath ;
819853 if ( status . type === UpToDateStatusType . UpToDate && ! context . options . force ) {
820854 // Up to date, skip
821855 if ( options . dry ) {
822856 // In a dry build, inform the user of this fact
823- reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Project_0_is_up_to_date ) ) ;
857+ reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Project_0_is_up_to_date , projName ) ) ;
824858 }
825859 continue ;
826860 }
@@ -831,10 +865,12 @@ namespace ts {
831865 continue ;
832866 }
833867
834- const result = buildSingleProject ( next ) ;
835- if ( result & BuildResultFlags . AnyErrors ) {
836- break ;
868+ if ( status . type === UpToDateStatusType . UpstreamBlocked ) {
869+ context . verbose ( Diagnostics . Skipping_build_of_project_0_because_its_upstream_project_1_has_errors , projName , status . upstreamProjectName ) ;
870+ continue ;
837871 }
872+
873+ buildSingleProject ( next ) ;
838874 }
839875
840876 function getNext ( ) : ResolvedConfigFileName | undefined {
@@ -889,9 +925,13 @@ namespace ts {
889925 case UpToDateStatusType . UpToDateWithUpstreamTypes :
890926 context . verbose ( Diagnostics . Project_0_is_up_to_date_with_its_upstream_types , configFileName ) ;
891927 return ;
892- case UpToDateStatusType . UpstreamOutOfDate :
928+ case UpToDateStatusType . UpstreamOutOfDate :
893929 context . verbose ( Diagnostics . Project_0_is_up_to_date_with_its_upstream_types , configFileName ) ;
894930 return ;
931+ case UpToDateStatusType . UpstreamBlocked :
932+ context . verbose ( Diagnostics . Project_0_can_t_be_built_because_it_depends_on_a_project_with_errors , configFileName ) ;
933+ return ;
934+
895935 default :
896936 throw new Error ( `Invalid build status - ${ UpToDateStatusType [ status . type ] } ` ) ;
897937 }
0 commit comments