11namespace ts {
2+ /**
3+ * Branded string for keeping track of when we've turned an ambiguous path
4+ * specified like "./blah" to an absolute path to an actual
5+ * tsconfig file, e.g. "/root/blah/tsconfig.json"
6+ */
27 type ResolvedConfigFileName = string & { _isResolvedConfigFileName : never } ;
38
49 const minimumDate = new Date ( - 8640000000000000 ) ;
510 const maximumDate = new Date ( 8640000000000000 ) ;
611
712 /**
813 * A BuildContext tracks what's going on during the course of a build.
9- * The primary thing we track here is which files were written to,
10- * but unchanged, because this enables fast downstream updates
14+ *
15+ * Callers may invoke any number of build requests within the same context;
16+ * until the context is reset, each project will only be built at most once.
17+ *
18+ * Example: In a standard setup where project B depends on project A, and both are out of date,
19+ * a failed build of A will result in A remaining out of date. When we try to build
20+ * B, we should immediately bail instead of recomputing A's up-to-date status again.
21+ *
22+ * This also matters for performing fast (i.e. fake) downstream builds of projects
23+ * when their upstream .d.ts files haven't changed content (but have newer timestamps)
1124 */
1225 export interface BuildContext {
1326 options : BuildOptions ;
@@ -21,6 +34,9 @@ namespace ts {
2134 */
2235 projectStatus : FileMap < UpToDateStatus > ;
2336
37+ /**
38+ * Issue a verbose diagnostic message. No-ops when options.verbose is false.
39+ */
2440 verbose ( diag : DiagnosticMessage , ...args : any [ ] ) : void ;
2541 }
2642
@@ -74,86 +90,86 @@ namespace ts {
7490 }
7591
7692 type UpToDateStatus =
77- | StatusUnbuildable
78- | StatusUpToDate
79- | StatusOutputMissing
80- | StatusOutOfDateWithSelf
81- | StatusOutOfDateWithUpstream
82- | StatusUpstreamOutOfDate
83- | StatusUpstreamBlocked ;
84-
85- /**
86- * The project can't be built at all in its current state. For example,
87- * its config file cannot be parsed, or it has a syntax error or missing file
88- */
89- interface StatusUnbuildable {
90- type : UpToDateStatusType . Unbuildable ;
91- reason : string ;
92- }
93+ | Status . Unbuildable
94+ | Status . UpToDate
95+ | Status . OutputMissing
96+ | Status . OutOfDateWithSelf
97+ | Status . OutOfDateWithUpstream
98+ | Status . UpstreamOutOfDate
99+ | Status . UpstreamBlocked ;
100+
101+ namespace Status {
102+ /**
103+ * The project can't be built at all in its current state. For example,
104+ * its config file cannot be parsed, or it has a syntax error or missing file
105+ */
106+ export interface Unbuildable {
107+ type : UpToDateStatusType . Unbuildable ;
108+ reason : string ;
109+ }
93110
94- /**
95- * The project is up to date with respect to its inputs.
96- * We track what the newest input file is.
97- */
98- interface StatusUpToDate {
99- type : UpToDateStatusType . UpToDate | UpToDateStatusType . UpToDateWithUpstreamTypes ;
100- newestInputFileTime : Date ;
101- newestDeclarationFileContentChangedTime : Date ;
102- newestOutputFileTime : Date ;
103- }
111+ /**
112+ * The project is up to date with respect to its inputs.
113+ * We track what the newest input file is.
114+ */
115+ export interface UpToDate {
116+ type : UpToDateStatusType . UpToDate | UpToDateStatusType . UpToDateWithUpstreamTypes ;
117+ newestInputFileTime : Date ;
118+ newestDeclarationFileContentChangedTime : Date ;
119+ newestOutputFileTime : Date ;
120+ }
104121
105- /**
106- * One or more of the outputs of the project does not exist.
107- */
108- interface StatusOutputMissing {
109- type : UpToDateStatusType . OutputMissing ;
110122 /**
111- * The name of the first output file that didn't exist
123+ * One or more of the outputs of the project does not exist.
112124 */
113- missingOutputFileName : string ;
114- }
125+ export interface OutputMissing {
126+ type : UpToDateStatusType . OutputMissing ;
127+ /**
128+ * The name of the first output file that didn't exist
129+ */
130+ missingOutputFileName : string ;
131+ }
115132
116- /**
117- * One or more of the project's outputs is older than its newest input.
118- */
119- interface StatusOutOfDateWithSelf {
120- type : UpToDateStatusType . OutOfDateWithSelf ;
121- outOfDateOutputFileName : string ;
122- newerInputFileName : string ;
123- }
133+ /**
134+ * One or more of the project's outputs is older than its newest input.
135+ */
136+ export interface OutOfDateWithSelf {
137+ type : UpToDateStatusType . OutOfDateWithSelf ;
138+ outOfDateOutputFileName : string ;
139+ newerInputFileName : string ;
140+ }
124141
125- /**
126- * This project depends on an out-of-date project, so shouldn't be built yet
127- */
128- interface StatusUpstreamOutOfDate {
129- type : UpToDateStatusType . UpstreamOutOfDate ;
130- upstreamProjectName : string ;
131- }
142+ /**
143+ * This project depends on an out-of-date project, so shouldn't be built yet
144+ */
145+ export interface UpstreamOutOfDate {
146+ type : UpToDateStatusType . UpstreamOutOfDate ;
147+ upstreamProjectName : string ;
148+ }
132149
133- /**
134- * This project depends an upstream project with build errors
135- */
136- interface StatusUpstreamBlocked {
137- type : UpToDateStatusType . UpstreamBlocked ;
138- upstreamProjectName : string ;
139- }
150+ /**
151+ * This project depends an upstream project with build errors
152+ */
153+ export interface UpstreamBlocked {
154+ type : UpToDateStatusType . UpstreamBlocked ;
155+ upstreamProjectName : string ;
156+ }
140157
141- /**
142- * One or more of the project's outputs is older than the newest output of
143- * an upstream project.
144- */
145- interface StatusOutOfDateWithUpstream {
146- type : UpToDateStatusType . OutOfDateWithUpstream ;
147- outOfDateOutputFileName : string ;
148- newerProjectName : string ;
158+ /**
159+ * One or more of the project's outputs is older than the newest output of
160+ * an upstream project.
161+ */
162+ export interface OutOfDateWithUpstream {
163+ type : UpToDateStatusType . OutOfDateWithUpstream ;
164+ outOfDateOutputFileName : string ;
165+ newerProjectName : string ;
166+ }
149167 }
150168
151169 interface FileMap < T > {
152170 setValue ( fileName : string , value : T ) : void ;
153171 getValue ( fileName : string ) : T | never ;
154172 getValueOrUndefined ( fileName : string ) : T | undefined ;
155- getValueOrDefault ( fileName : string , defaultValue : T ) : T ;
156- tryGetValue ( fileName : string ) : [ false , undefined ] | [ true , T ] ;
157173 }
158174
159175 /**
@@ -167,8 +183,6 @@ namespace ts {
167183 setValue,
168184 getValue,
169185 getValueOrUndefined,
170- getValueOrDefault,
171- tryGetValue
172186 } ;
173187
174188 function setValue ( fileName : string , value : T ) {
@@ -194,26 +208,6 @@ namespace ts {
194208 return undefined ;
195209 }
196210 }
197-
198- function getValueOrDefault ( fileName : string , defaultValue : T ) : T {
199- const f = normalizePath ( fileName ) ;
200- if ( f in lookup ) {
201- return lookup [ f ] ;
202- }
203- else {
204- return defaultValue ;
205- }
206- }
207-
208- function tryGetValue ( fileName : string ) : [ false , undefined ] | [ true , T ] {
209- const f = normalizePath ( fileName ) ;
210- if ( f in lookup ) {
211- return [ true as true , lookup [ f ] ] ;
212- }
213- else {
214- return [ false as false , undefined ] ;
215- }
216- }
217211 }
218212
219213 export function createDependencyMapper ( ) {
@@ -402,13 +396,13 @@ namespace ts {
402396 }
403397 }
404398
405- export function createSolutionBuilder ( host : CompilerHost , reportDiagnostic : DiagnosticReporter , options : BuildOptions ) {
399+ export function createSolutionBuilder ( host : CompilerHost , reportDiagnostic : DiagnosticReporter , defaultOptions : BuildOptions ) {
406400 if ( ! host . getModifiedTime || ! host . setModifiedTime ) {
407401 throw new Error ( "Host must support timestamp APIs" ) ;
408402 }
409403
410404 const configFileCache = createConfigFileCache ( host ) ;
411- let context = createBuildContext ( options , reportDiagnostic ) ;
405+ let context = createBuildContext ( defaultOptions , reportDiagnostic ) ;
412406
413407 return {
414408 getUpToDateStatus,
@@ -418,8 +412,8 @@ namespace ts {
418412 resetBuildContext
419413 } ;
420414
421- function resetBuildContext ( ) {
422- context = createBuildContext ( options , reportDiagnostic ) ;
415+ function resetBuildContext ( opts = defaultOptions ) {
416+ context = createBuildContext ( opts , reportDiagnostic ) ;
423417 }
424418
425419 function getUpToDateStatusOfFile ( configFileName : ResolvedConfigFileName ) : UpToDateStatus {
@@ -798,7 +792,7 @@ namespace ts {
798792 }
799793
800794 if ( context . options . dry ) {
801- reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Would_delete_the_following_files_Colon_0 , filesToDelete . map ( f => `\r\n * ${ f } ` ) . join ( "" ) ) ) ;
795+ reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Would_delete_the_following_files_Colon_0 , filesToDelete . map ( f => `\r\n * ${ f } ` ) . join ( "" ) ) ) ;
802796 }
803797 else {
804798 if ( ! host . deleteFile ) {
@@ -852,7 +846,7 @@ namespace ts {
852846 const projName = proj . options . configFilePath ;
853847 if ( status . type === UpToDateStatusType . UpToDate && ! context . options . force ) {
854848 // Up to date, skip
855- if ( options . dry ) {
849+ if ( defaultOptions . dry ) {
856850 // In a dry build, inform the user of this fact
857851 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Project_0_is_up_to_date , projName ) ) ;
858852 }
@@ -889,6 +883,9 @@ namespace ts {
889883 }
890884 }
891885
886+ /**
887+ * Report the build ordering inferred from the current project graph if we're in verbose mode
888+ */
892889 function reportBuildQueue ( graph : DependencyGraph ) {
893890 if ( ! context . options . verbose ) return ;
894891
@@ -902,6 +899,9 @@ namespace ts {
902899 context . verbose ( Diagnostics . Sorted_list_of_input_projects_Colon_0 , names . map ( s => "\r\n * " + s ) . join ( "" ) ) ;
903900 }
904901
902+ /**
903+ * Report the up-to-date status of a project if we're in verbose mode
904+ */
905905 function reportProjectStatus ( configFileName : string , status : UpToDateStatus ) {
906906 if ( ! context . options . verbose ) return ;
907907 switch ( status . type ) {
@@ -931,9 +931,12 @@ namespace ts {
931931 case UpToDateStatusType . UpstreamBlocked :
932932 context . verbose ( Diagnostics . Project_0_can_t_be_built_because_it_depends_on_a_project_with_errors , configFileName ) ;
933933 return ;
934-
934+ case UpToDateStatusType . Unbuildable :
935+ // TODO different error
936+ context . verbose ( Diagnostics . Project_0_can_t_be_built_because_it_depends_on_a_project_with_errors , configFileName ) ;
937+ return ;
935938 default :
936- throw new Error ( `Invalid build status - ${ UpToDateStatusType [ status . type ] } ` ) ;
939+ assertTypeIsNever ( status ) ;
937940 }
938941 }
939942 }
0 commit comments