@@ -248,14 +248,14 @@ namespace ts {
248248 }
249249
250250 function getOutputDeclarationFileName ( inputFileName : string , configFile : ParsedCommandLine ) {
251- const relativePath = getRelativePathFromDirectory ( rootDirOfOptions ( configFile . options , configFile . options . configFilePath ) , inputFileName , /*ignoreCase*/ true ) ;
252- const outputPath = resolvePath ( configFile . options . declarationDir || configFile . options . outDir || getDirectoryPath ( configFile . options . configFilePath ) , relativePath ) ;
251+ const relativePath = getRelativePathFromDirectory ( rootDirOfOptions ( configFile . options , configFile . options . configFilePath ! ) , inputFileName , /*ignoreCase*/ true ) ;
252+ const outputPath = resolvePath ( configFile . options . declarationDir || configFile . options . outDir || getDirectoryPath ( configFile . options . configFilePath ! ) , relativePath ) ;
253253 return changeExtension ( outputPath , ".d.ts" ) ;
254254 }
255255
256256 function getOutputJavaScriptFileName ( inputFileName : string , configFile : ParsedCommandLine ) {
257- const relativePath = getRelativePathFromDirectory ( rootDirOfOptions ( configFile . options , configFile . options . configFilePath ) , inputFileName , /*ignoreCase*/ true ) ;
258- const outputPath = resolvePath ( configFile . options . outDir || getDirectoryPath ( configFile . options . configFilePath ) , relativePath ) ;
257+ const relativePath = getRelativePathFromDirectory ( rootDirOfOptions ( configFile . options , configFile . options . configFilePath ! ) , inputFileName , /*ignoreCase*/ true ) ;
258+ const outputPath = resolvePath ( configFile . options . outDir || getDirectoryPath ( configFile . options . configFilePath ! ) , relativePath ) ;
259259 return changeExtension ( outputPath , ( fileExtensionIs ( inputFileName , ".tsx" ) && configFile . options . jsx === JsxEmit . Preserve ) ? ".jsx" : ".js" ) ;
260260 }
261261
@@ -276,7 +276,9 @@ namespace ts {
276276 }
277277
278278 function getOutFileOutputs ( project : ParsedCommandLine ) : ReadonlyArray < string > {
279- Debug . assert ( ! ! project . options . outFile , "outFile must be set" ) ;
279+ if ( ! project . options . outFile ) {
280+ throw new Error ( "Assert - outFile must be set" ) ;
281+ }
280282 const outputs : string [ ] = [ ] ;
281283 outputs . push ( project . options . outFile ) ;
282284 if ( project . options . declaration ) {
@@ -328,9 +330,7 @@ namespace ts {
328330 options,
329331 projectStatus : createFileMap ( ) ,
330332 unchangedOutputs : createFileMap ( ) ,
331- verbose : options . verbose ? ( diag , ...args ) => {
332- verboseDiag ( createCompilerDiagnostic ( diag , ...args ) ) ;
333- } : ( ) => undefined
333+ verbose : verboseDiag ? ( diag , ...args ) => verboseDiag ( createCompilerDiagnostic ( diag , ...args ) ) : ( ) => undefined
334334 } ;
335335 }
336336
@@ -379,6 +379,11 @@ namespace ts {
379379 function addProject ( projectSpecification : string ) {
380380 const fileName = resolvePath ( host . getCurrentDirectory ( ) , projectSpecification ) ;
381381 const refPath = resolveProjectReferencePath ( host , { path : fileName } ) ;
382+ if ( ! refPath ) {
383+ reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . File_0_does_not_exist , projectSpecification ) ) ;
384+ return ;
385+ }
386+
382387 if ( ! host . fileExists ( refPath ) ) {
383388 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . File_0_does_not_exist , fileName ) ) ;
384389 }
@@ -388,6 +393,10 @@ namespace ts {
388393 }
389394
390395 export function createSolutionBuilder ( host : CompilerHost , reportDiagnostic : DiagnosticReporter , options : BuildOptions ) {
396+ if ( ! host . getModifiedTime || ! host . setModifiedTime ) {
397+ throw new Error ( "Host must support timestamp APIs" ) ;
398+ }
399+
391400 const configFileCache = createConfigFileCache ( host ) ;
392401 let context = createBuildContext ( options , reportDiagnostic ) ;
393402
@@ -407,13 +416,17 @@ namespace ts {
407416 return getUpToDateStatus ( configFileCache . parseConfigFile ( configFileName ) ) ;
408417 }
409418
410- function getUpToDateStatus ( project : ParsedCommandLine ) : UpToDateStatus {
411- const prior = context . projectStatus . getValueOrUndefined ( project . options . configFilePath ) ;
419+ function getUpToDateStatus ( project : ParsedCommandLine | undefined ) : UpToDateStatus {
420+ if ( project === undefined ) {
421+ return { type : UpToDateStatusType . Unbuildable , reason : "File deleted mid-build" } ;
422+ }
423+
424+ const prior = context . projectStatus . getValueOrUndefined ( project . options . configFilePath ! ) ;
412425 if ( prior !== undefined ) {
413426 return prior ;
414427 }
415428 const actual = getUpToDateStatusWorker ( project ) ;
416- context . projectStatus . setValue ( project . options . configFilePath , actual ) ;
429+ context . projectStatus . setValue ( project . options . configFilePath ! , actual ) ;
417430 return actual ;
418431 }
419432
@@ -442,7 +455,7 @@ namespace ts {
442455 } ;
443456 }
444457
445- const inputTime = host . getModifiedTime ( inputFile ) ;
458+ const inputTime = host . getModifiedTime ! ( inputFile ) ;
446459 if ( inputTime > newestInputFileTime ) {
447460 newestInputFileName = inputFile ;
448461 newestInputFileTime = inputTime ;
@@ -466,7 +479,7 @@ namespace ts {
466479 } ;
467480 }
468481
469- const outputTime = host . getModifiedTime ( output ) ;
482+ const outputTime = host . getModifiedTime ! ( output ) ;
470483 // If an output is older than the newest input, we can stop checking
471484 if ( outputTime < newestInputFileTime ) {
472485 return {
@@ -492,7 +505,7 @@ namespace ts {
492505 newestDeclarationFileContentChangedTime = newer ( unchangedTime , newestDeclarationFileContentChangedTime ) ;
493506 }
494507 else {
495- newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , host . getModifiedTime ( output ) ) ;
508+ newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , host . getModifiedTime ! ( output ) ) ;
496509 }
497510 }
498511 }
@@ -609,10 +622,10 @@ namespace ts {
609622 }
610623
611624 // TODO Accept parsedCommandLine instead?
612- function buildSingleProject ( proj : ResolvedConfigFileName ) {
625+ function buildSingleProject ( proj : ResolvedConfigFileName ) : BuildResultFlags {
613626 if ( context . options . dry ) {
614627 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Would_build_project_0 , proj ) ) ;
615- return ;
628+ return BuildResultFlags . Success ;
616629 }
617630
618631 context . verbose ( Diagnostics . Building_project_0 , proj ) ;
@@ -707,17 +720,17 @@ namespace ts {
707720 let priorNewestUpdateTime = minimumDate ;
708721 for ( const file of outputs ) {
709722 if ( isDeclarationFile ( file ) ) {
710- priorNewestUpdateTime = newer ( priorNewestUpdateTime , host . getModifiedTime ( file ) ) ;
723+ priorNewestUpdateTime = newer ( priorNewestUpdateTime , host . getModifiedTime ! ( file ) ) ;
711724 }
712- host . setModifiedTime ( file , now ) ;
725+ host . setModifiedTime ! ( file , now ) ;
713726 }
714727
715- context . projectStatus . setValue ( proj . options . configFilePath , { type : UpToDateStatusType . UpToDate , newestDeclarationFileContentChangedTime : priorNewestUpdateTime } as UpToDateStatus ) ;
728+ context . projectStatus . setValue ( proj . options . configFilePath ! , { type : UpToDateStatusType . UpToDate , newestDeclarationFileContentChangedTime : priorNewestUpdateTime } as UpToDateStatus ) ;
716729 }
717730
718731 function getFilesToClean ( configFileNames : ResolvedConfigFileName [ ] ) : string [ ] | undefined {
719732 const resolvedNames : ResolvedConfigFileName [ ] | undefined = resolveProjectNames ( configFileNames ) ;
720- if ( resolvedNames === undefined ) return ;
733+ if ( resolvedNames === undefined ) return undefined ;
721734
722735 // Get the same graph for cleaning we'd use for building
723736 const graph = createDependencyGraph ( resolvedNames ) ;
@@ -726,6 +739,10 @@ namespace ts {
726739 for ( const level of graph . buildQueue ) {
727740 for ( const proj of level ) {
728741 const parsed = configFileCache . parseConfigFile ( proj ) ;
742+ if ( parsed === undefined ) {
743+ // File has gone missing; fine to ignore here
744+ continue ;
745+ }
729746 const outputs = getAllProjectOutputs ( parsed ) ;
730747 for ( const output of outputs ) {
731748 if ( host . fileExists ( output ) ) {
@@ -742,6 +759,9 @@ namespace ts {
742759 if ( resolvedNames === undefined ) return ;
743760
744761 const filesToDelete = getFilesToClean ( resolvedNames ) ;
762+ if ( filesToDelete === undefined ) {
763+ return ;
764+ }
745765
746766 if ( context . options . dry ) {
747767 reportDiagnostic ( createCompilerDiagnostic ( Diagnostics . Would_delete_the_following_files_Colon_0 , filesToDelete . map ( f => `\r\n * ${ f } ` ) . join ( "" ) ) ) ;
@@ -786,9 +806,13 @@ namespace ts {
786806 const queue = graph . buildQueue ;
787807 reportBuildQueue ( graph ) ;
788808
789- let next : ResolvedConfigFileName ;
809+ let next : ResolvedConfigFileName | undefined ;
790810 while ( next = getNext ( ) ) {
791811 const proj = configFileCache . parseConfigFile ( next ) ;
812+ if ( proj === undefined ) {
813+ break ;
814+ }
815+
792816 const status = getUpToDateStatus ( proj ) ;
793817 reportProjectStatus ( next , status ) ;
794818
0 commit comments