@@ -264,15 +264,10 @@ namespace ts {
264264 export interface SolutionBuilderWithWatchHost < T extends BuilderProgram > extends SolutionBuilderHostBase < T > , WatchHost {
265265 }
266266
267- export interface SolutionBuilderResult < T > {
268- project : ResolvedConfigFileName ;
269- result : T ;
270- }
271-
272- export interface SolutionBuilder {
267+ export interface SolutionBuilder < T extends BuilderProgram > {
273268 build ( project ?: string , cancellationToken ?: CancellationToken ) : ExitStatus ;
274269 clean ( project ?: string ) : ExitStatus ;
275- buildNextProject ( cancellationToken ?: CancellationToken ) : SolutionBuilderResult < ExitStatus > | undefined ;
270+ getNextInvalidatedProject ( cancellationToken ?: CancellationToken ) : InvalidatedProject < T > | undefined ;
276271
277272 // Currently used for testing but can be made public if needed:
278273 /*@internal */ getBuildOrder ( ) : ReadonlyArray < ResolvedConfigFileName > ;
@@ -325,11 +320,11 @@ namespace ts {
325320 return result ;
326321 }
327322
328- export function createSolutionBuilder < T extends BuilderProgram > ( host : SolutionBuilderHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder {
323+ export function createSolutionBuilder < T extends BuilderProgram > ( host : SolutionBuilderHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder < T > {
329324 return createSolutionBuilderWorker ( /*watch*/ false , host , rootNames , defaultOptions ) ;
330325 }
331326
332- export function createSolutionBuilderWithWatch < T extends BuilderProgram > ( host : SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder {
327+ export function createSolutionBuilderWithWatch < T extends BuilderProgram > ( host : SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder < T > {
333328 return createSolutionBuilderWorker ( /*watch*/ true , host , rootNames , defaultOptions ) ;
334329 }
335330
@@ -380,6 +375,7 @@ namespace ts {
380375 allProjectBuildPending : boolean ;
381376 needsSummary : boolean ;
382377 watchAllProjectsPending : boolean ;
378+ currentInvalidatedProject : InvalidatedProject < T > | undefined ;
383379
384380 // Watch state
385381 readonly watch : boolean ;
@@ -452,6 +448,7 @@ namespace ts {
452448 allProjectBuildPending : true ,
453449 needsSummary : true ,
454450 watchAllProjectsPending : watch ,
451+ currentInvalidatedProject : undefined ,
455452
456453 // Watch state
457454 watch,
@@ -654,36 +651,38 @@ namespace ts {
654651 }
655652 }
656653
657- const enum InvalidatedProjectKind {
654+ export enum InvalidatedProjectKind {
658655 Build ,
659656 UpdateBundle ,
660657 UpdateOutputFileStamps
661658 }
662659
663- interface InvalidatedProjectBase {
660+ export interface InvalidatedProjectBase {
664661 readonly kind : InvalidatedProjectKind ;
665662 readonly project : ResolvedConfigFileName ;
666- readonly projectPath : ResolvedConfigFilePath ;
663+ /*@internal */ readonly projectPath : ResolvedConfigFilePath ;
664+ /*@internal */ readonly buildOrder : readonly ResolvedConfigFileName [ ] ;
667665 /**
668666 * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly
669667 */
670- done ( cancellationToken ?: CancellationToken ) : void ;
668+ done ( cancellationToken ?: CancellationToken ) : ExitStatus ;
669+ getCompilerOptions ( ) : CompilerOptions ;
670+ getCurrentDirectory ( ) : string ;
671671 }
672672
673- interface UpdateOutputFileStampsProject extends InvalidatedProjectBase {
673+ export interface UpdateOutputFileStampsProject extends InvalidatedProjectBase {
674674 readonly kind : InvalidatedProjectKind . UpdateOutputFileStamps ;
675675 updateOutputFileStatmps ( ) : void ;
676676 }
677677
678- interface BuildInvalidedProject < T extends BuilderProgram = BuilderProgram > extends InvalidatedProjectBase {
678+ export interface BuildInvalidedProject < T extends BuilderProgram > extends InvalidatedProjectBase {
679679 readonly kind : InvalidatedProjectKind . Build ;
680680 /*
681681 * Emitting with this builder program without the api provided for this project
682682 * can result in build system going into invalid state as files written reflect the state of the project
683683 */
684684 getBuilderProgram ( ) : T | undefined ;
685685 getProgram ( ) : Program | undefined ;
686- getCompilerOptions ( ) : CompilerOptions ;
687686 getSourceFile ( fileName : string ) : SourceFile | undefined ;
688687 getSourceFiles ( ) : ReadonlyArray < SourceFile > ;
689688 getOptionsDiagnostics ( cancellationToken ?: CancellationToken ) : ReadonlyArray < Diagnostic > ;
@@ -704,22 +703,41 @@ namespace ts {
704703 emit ( targetSourceFile ?: SourceFile , writeFile ?: WriteFileCallback , cancellationToken ?: CancellationToken , emitOnlyDtsFiles ?: boolean , customTransformers ?: CustomTransformers ) : EmitResult | undefined ;
705704 // TODO(shkamat):: investigate later if we can emit even when there are declaration diagnostics
706705 // emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): AffectedFileResult<EmitResult>;
707- getCurrentDirectory ( ) : string ;
708706 }
709707
710- interface UpdateBundleProject < T extends BuilderProgram = BuilderProgram > extends InvalidatedProjectBase {
708+ export interface UpdateBundleProject < T extends BuilderProgram > extends InvalidatedProjectBase {
711709 readonly kind : InvalidatedProjectKind . UpdateBundle ;
712710 emit ( writeFile ?: WriteFileCallback , customTransformers ?: CustomTransformers ) : EmitResult | BuildInvalidedProject < T > | undefined ;
713711 }
714712
715- type InvalidatedProject < T extends BuilderProgram = BuilderProgram > = UpdateOutputFileStampsProject | BuildInvalidedProject < T > | UpdateBundleProject < T > ;
713+ export type InvalidatedProject < T extends BuilderProgram > = UpdateOutputFileStampsProject | BuildInvalidedProject < T > | UpdateBundleProject < T > ;
716714
717- function createUpdateOutputFileStampsProject ( state : SolutionBuilderState , project : ResolvedConfigFileName , projectPath : ResolvedConfigFilePath , config : ParsedCommandLine ) : UpdateOutputFileStampsProject {
715+ function doneInvalidatedProject (
716+ state : SolutionBuilderState ,
717+ projectPath : ResolvedConfigFilePath
718+ ) {
719+ state . projectPendingBuild . delete ( projectPath ) ;
720+ state . currentInvalidatedProject = undefined ;
721+ return state . diagnostics . has ( projectPath ) ?
722+ ExitStatus . DiagnosticsPresent_OutputsSkipped :
723+ ExitStatus . Success ;
724+ }
725+
726+ function createUpdateOutputFileStampsProject (
727+ state : SolutionBuilderState ,
728+ project : ResolvedConfigFileName ,
729+ projectPath : ResolvedConfigFilePath ,
730+ config : ParsedCommandLine ,
731+ buildOrder : readonly ResolvedConfigFileName [ ]
732+ ) : UpdateOutputFileStampsProject {
718733 let updateOutputFileStampsPending = true ;
719734 return {
720735 kind : InvalidatedProjectKind . UpdateOutputFileStamps ,
721736 project,
722737 projectPath,
738+ buildOrder,
739+ getCompilerOptions : ( ) => config . options ,
740+ getCurrentDirectory : ( ) => state . currentDirectory ,
723741 updateOutputFileStatmps : ( ) => {
724742 updateOutputTimestamps ( state , config , projectPath ) ;
725743 updateOutputFileStampsPending = false ;
@@ -728,7 +746,7 @@ namespace ts {
728746 if ( updateOutputFileStampsPending ) {
729747 updateOutputTimestamps ( state , config , projectPath ) ;
730748 }
731- state . projectPendingBuild . delete ( projectPath ) ;
749+ return doneInvalidatedProject ( state , projectPath ) ;
732750 }
733751 } ;
734752 }
@@ -763,12 +781,14 @@ namespace ts {
763781 kind,
764782 project,
765783 projectPath,
784+ buildOrder,
785+ getCompilerOptions : ( ) => config . options ,
786+ getCurrentDirectory : ( ) => state . currentDirectory ,
766787 getBuilderProgram : ( ) => withProgramOrUndefined ( identity ) ,
767788 getProgram : ( ) =>
768789 withProgramOrUndefined (
769790 program => program . getProgramOrUndefined ( )
770791 ) ,
771- getCompilerOptions : ( ) => config . options ,
772792 getSourceFile : fileName =>
773793 withProgramOrUndefined (
774794 program => program . getSourceFile ( fileName )
@@ -817,26 +837,27 @@ namespace ts {
817837 if ( step !== Step . Emit ) return undefined ;
818838 return emit ( writeFile , cancellationToken , customTransformers ) ;
819839 } ,
820- getCurrentDirectory : ( ) => state . currentDirectory ,
821- done : cancellationToken => {
822- executeSteps ( Step . Done , cancellationToken ) ;
823- state . projectPendingBuild . delete ( projectPath ) ;
824- }
840+ done
825841 } :
826842 {
827843 kind,
828844 project,
829845 projectPath,
846+ buildOrder,
847+ getCompilerOptions : ( ) => config . options ,
848+ getCurrentDirectory : ( ) => state . currentDirectory ,
830849 emit : ( writeFile : WriteFileCallback | undefined , customTransformers : CustomTransformers | undefined ) => {
831850 if ( step !== Step . EmitBundle ) return invalidatedProjectOfBundle ;
832851 return emitBundle ( writeFile , customTransformers ) ;
833852 } ,
834- done : cancellationToken => {
835- executeSteps ( Step . Done , cancellationToken ) ;
836- state . projectPendingBuild . delete ( projectPath ) ;
837- }
853+ done,
838854 } ;
839855
856+ function done ( cancellationToken ?: CancellationToken ) {
857+ executeSteps ( Step . Done , cancellationToken ) ;
858+ return doneInvalidatedProject ( state , projectPath ) ;
859+ }
860+
840861 function withProgramOrUndefined < U > ( action : ( program : T ) => U | undefined ) : U | undefined {
841862 executeSteps ( Step . CreateProgram ) ;
842863 return program && action ( program ) ;
@@ -1152,6 +1173,12 @@ namespace ts {
11521173
11531174 function getNextInvalidatedProject < T extends BuilderProgram > ( state : SolutionBuilderState < T > , buildOrder : readonly ResolvedConfigFileName [ ] ) : InvalidatedProject < T > | undefined {
11541175 if ( ! state . projectPendingBuild . size ) return undefined ;
1176+ if ( state . currentInvalidatedProject ) {
1177+ // Only if same buildOrder the currentInvalidated project can be sent again
1178+ return arrayIsEqualTo ( state . currentInvalidatedProject . buildOrder , buildOrder ) ?
1179+ state . currentInvalidatedProject :
1180+ undefined ;
1181+ }
11551182
11561183 const { options, projectPendingBuild } = state ;
11571184 for ( let projectIndex = 0 ; projectIndex < buildOrder . length ; projectIndex ++ ) {
@@ -1200,7 +1227,8 @@ namespace ts {
12001227 state ,
12011228 project ,
12021229 projectPath ,
1203- config
1230+ config ,
1231+ buildOrder
12041232 ) ;
12051233 }
12061234 }
@@ -1635,20 +1663,6 @@ namespace ts {
16351663 }
16361664 }
16371665
1638- function buildNextProject ( state : SolutionBuilderState , cancellationToken ?: CancellationToken ) : SolutionBuilderResult < ExitStatus > | undefined {
1639- setupInitialBuild ( state , cancellationToken ) ;
1640- const invalidatedProject = getNextInvalidatedProject ( state , getBuildOrder ( state ) ) ;
1641- if ( ! invalidatedProject ) return undefined ;
1642-
1643- invalidatedProject . done ( cancellationToken ) ;
1644- return {
1645- project : invalidatedProject . project ,
1646- result : state . diagnostics . has ( invalidatedProject . projectPath ) ?
1647- ExitStatus . DiagnosticsPresent_OutputsSkipped :
1648- ExitStatus . Success
1649- } ;
1650- }
1651-
16521666 function build ( state : SolutionBuilderState , project ?: string , cancellationToken ?: CancellationToken ) : ExitStatus {
16531667 const buildOrder = getBuildOrderFor ( state , project ) ;
16541668 if ( ! buildOrder ) return ExitStatus . InvalidProject_OutputsSkipped ;
@@ -1883,14 +1897,17 @@ namespace ts {
18831897 * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
18841898 * can dynamically add/remove other projects based on changes on the rootNames' references
18851899 */
1886- function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : false , host : SolutionBuilderHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder ;
1887- function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : true , host : SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder ;
1888- function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : boolean , hostOrHostWithWatch : SolutionBuilderHost < T > | SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , options : BuildOptions ) : SolutionBuilder {
1900+ function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : false , host : SolutionBuilderHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder < T > ;
1901+ function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : true , host : SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions ) : SolutionBuilder < T > ;
1902+ function createSolutionBuilderWorker < T extends BuilderProgram > ( watch : boolean , hostOrHostWithWatch : SolutionBuilderHost < T > | SolutionBuilderWithWatchHost < T > , rootNames : ReadonlyArray < string > , options : BuildOptions ) : SolutionBuilder < T > {
18891903 const state = createSolutionBuilderState ( watch , hostOrHostWithWatch , rootNames , options ) ;
18901904 return {
18911905 build : ( project , cancellationToken ) => build ( state , project , cancellationToken ) ,
18921906 clean : project => clean ( state , project ) ,
1893- buildNextProject : cancellationToken => buildNextProject ( state , cancellationToken ) ,
1907+ getNextInvalidatedProject : cancellationToken => {
1908+ setupInitialBuild ( state , cancellationToken ) ;
1909+ return getNextInvalidatedProject ( state , getBuildOrder ( state ) ) ;
1910+ } ,
18941911 getBuildOrder : ( ) => getBuildOrder ( state ) ,
18951912 getUpToDateStatusOfProject : project => {
18961913 const configFileName = resolveProjectName ( state , project ) ;
0 commit comments