@@ -388,16 +388,27 @@ namespace ts {
388
388
} ;
389
389
}
390
390
391
+ export interface SolutionBuilderHost extends CompilerHost {
392
+ getModifiedTime ( fileName : string ) : Date | undefined ;
393
+ setModifiedTime ( fileName : string , date : Date ) : void ;
394
+ deleteFile ( fileName : string ) : void ;
395
+ }
396
+
397
+ export function createSolutionBuilderHost ( system = sys ) {
398
+ const host = createCompilerHost ( { } , /*setParentNodes*/ undefined , system ) as SolutionBuilderHost ;
399
+ host . getModifiedTime = system . getModifiedTime ? path => system . getModifiedTime ! ( path ) : ( ) => undefined ;
400
+ host . setModifiedTime = system . setModifiedTime ? ( path , date ) => system . setModifiedTime ! ( path , date ) : noop ;
401
+ host . deleteFile = system . deleteFile ? path => system . deleteFile ! ( path ) : noop ;
402
+ return host ;
403
+ }
404
+
391
405
/**
392
406
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
393
407
* can dynamically add/remove other projects based on changes on the rootNames' references
394
408
*/
395
- export function createSolutionBuilder ( compilerHost : CompilerHost , buildHost : BuildHost , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions , system ?: System ) {
396
- if ( ! compilerHost . getModifiedTime || ! compilerHost . setModifiedTime ) {
397
- throw new Error ( "Host must support timestamp APIs" ) ;
398
- }
409
+ export function createSolutionBuilder ( host : SolutionBuilderHost , buildHost : BuildHost , rootNames : ReadonlyArray < string > , defaultOptions : BuildOptions , system ?: System ) {
399
410
400
- const configFileCache = createConfigFileCache ( compilerHost ) ;
411
+ const configFileCache = createConfigFileCache ( host ) ;
401
412
let context = createBuildContext ( defaultOptions ) ;
402
413
403
414
const existingWatchersForWildcards = createMap < WildcardDirectoryWatcher > ( ) ;
@@ -501,14 +512,14 @@ namespace ts {
501
512
let newestInputFileTime = minimumDate ;
502
513
// Get timestamps of input files
503
514
for ( const inputFile of project . fileNames ) {
504
- if ( ! compilerHost . fileExists ( inputFile ) ) {
515
+ if ( ! host . fileExists ( inputFile ) ) {
505
516
return {
506
517
type : UpToDateStatusType . Unbuildable ,
507
518
reason : `${ inputFile } does not exist`
508
519
} ;
509
520
}
510
521
511
- const inputTime = compilerHost . getModifiedTime ! ( inputFile ) || missingFileModifiedTime ;
522
+ const inputTime = host . getModifiedTime ( inputFile ) || missingFileModifiedTime ;
512
523
if ( inputTime > newestInputFileTime ) {
513
524
newestInputFileName = inputFile ;
514
525
newestInputFileTime = inputTime ;
@@ -535,12 +546,12 @@ namespace ts {
535
546
for ( const output of outputs ) {
536
547
// Output is missing; can stop checking
537
548
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
538
- if ( ! compilerHost . fileExists ( output ) ) {
549
+ if ( ! host . fileExists ( output ) ) {
539
550
missingOutputFileName = output ;
540
551
break ;
541
552
}
542
553
543
- const outputTime = compilerHost . getModifiedTime ! ( output ) || missingFileModifiedTime ;
554
+ const outputTime = host . getModifiedTime ( output ) || missingFileModifiedTime ;
544
555
if ( outputTime < oldestOutputFileTime ) {
545
556
oldestOutputFileTime = outputTime ;
546
557
oldestOutputFileName = output ;
@@ -568,7 +579,7 @@ namespace ts {
568
579
newestDeclarationFileContentChangedTime = newer ( unchangedTime , newestDeclarationFileContentChangedTime ) ;
569
580
}
570
581
else {
571
- const outputModifiedTime = compilerHost . getModifiedTime ! ( output ) || missingFileModifiedTime ;
582
+ const outputModifiedTime = host . getModifiedTime ( output ) || missingFileModifiedTime ;
572
583
newestDeclarationFileContentChangedTime = newer ( newestDeclarationFileContentChangedTime , outputModifiedTime ) ;
573
584
}
574
585
}
@@ -580,7 +591,7 @@ namespace ts {
580
591
if ( project . projectReferences ) {
581
592
for ( const ref of project . projectReferences ) {
582
593
usesPrepend = usesPrepend || ! ! ( ref . prepend ) ;
583
- const resolvedRef = resolveProjectReferencePath ( compilerHost , ref ) ;
594
+ const resolvedRef = resolveProjectReferencePath ( host , ref ) ;
584
595
const refStatus = getUpToDateStatus ( configFileCache . parseConfigFile ( resolvedRef ) ) ;
585
596
586
597
// An upstream project is blocked
@@ -809,7 +820,7 @@ namespace ts {
809
820
810
821
const programOptions : CreateProgramOptions = {
811
822
projectReferences : configFile . projectReferences ,
812
- host : compilerHost ,
823
+ host,
813
824
rootNames : configFile . fileNames ,
814
825
options : configFile . options
815
826
} ;
@@ -858,18 +869,18 @@ namespace ts {
858
869
program . emit ( /*targetSourceFile*/ undefined , ( fileName , content , writeBom , onError ) => {
859
870
let priorChangeTime : Date | undefined ;
860
871
861
- if ( ! anyDtsChanged && isDeclarationFile ( fileName ) && compilerHost . fileExists ( fileName ) ) {
862
- if ( compilerHost . readFile ( fileName ) === content ) {
872
+ if ( ! anyDtsChanged && isDeclarationFile ( fileName ) && host . fileExists ( fileName ) ) {
873
+ if ( host . readFile ( fileName ) === content ) {
863
874
// Check for unchanged .d.ts files
864
875
resultFlags &= ~ BuildResultFlags . DeclarationOutputUnchanged ;
865
- priorChangeTime = compilerHost . getModifiedTime && compilerHost . getModifiedTime ( fileName ) ;
876
+ priorChangeTime = host . getModifiedTime ( fileName ) ;
866
877
}
867
878
else {
868
879
anyDtsChanged = true ;
869
880
}
870
881
}
871
882
872
- compilerHost . writeFile ( fileName , content , writeBom , onError , emptyArray ) ;
883
+ host . writeFile ( fileName , content , writeBom , onError , emptyArray ) ;
873
884
if ( priorChangeTime !== undefined ) {
874
885
newestDeclarationFileContentChangedTime = newer ( priorChangeTime , newestDeclarationFileContentChangedTime ) ;
875
886
context . unchangedOutputs . setValue ( fileName , priorChangeTime ) ;
@@ -898,10 +909,10 @@ namespace ts {
898
909
let priorNewestUpdateTime = minimumDate ;
899
910
for ( const file of outputs ) {
900
911
if ( isDeclarationFile ( file ) ) {
901
- priorNewestUpdateTime = newer ( priorNewestUpdateTime , compilerHost . getModifiedTime ! ( file ) || missingFileModifiedTime ) ;
912
+ priorNewestUpdateTime = newer ( priorNewestUpdateTime , host . getModifiedTime ( file ) || missingFileModifiedTime ) ;
902
913
}
903
914
904
- compilerHost . setModifiedTime ! ( file , now ) ;
915
+ host . setModifiedTime ( file , now ) ;
905
916
}
906
917
907
918
context . projectStatus . setValue ( proj . options . configFilePath ! , { type : UpToDateStatusType . UpToDate , newestDeclarationFileContentChangedTime : priorNewestUpdateTime } as UpToDateStatus ) ;
@@ -924,7 +935,7 @@ namespace ts {
924
935
}
925
936
const outputs = getAllProjectOutputs ( parsed ) ;
926
937
for ( const output of outputs ) {
927
- if ( compilerHost . fileExists ( output ) ) {
938
+ if ( host . fileExists ( output ) ) {
928
939
filesToDelete . push ( output ) ;
929
940
}
930
941
}
@@ -958,25 +969,20 @@ namespace ts {
958
969
return ExitStatus . Success ;
959
970
}
960
971
961
- // Do this check later to allow --clean --dry to function even if the host can't delete files
962
- if ( ! compilerHost . deleteFile ) {
963
- throw new Error ( "Host does not support deleting files" ) ;
964
- }
965
-
966
972
for ( const output of filesToDelete ) {
967
- compilerHost . deleteFile ( output ) ;
973
+ host . deleteFile ( output ) ;
968
974
}
969
975
970
976
return ExitStatus . Success ;
971
977
}
972
978
973
979
function resolveProjectName ( name : string ) : ResolvedConfigFileName | undefined {
974
- const fullPath = resolvePath ( compilerHost . getCurrentDirectory ( ) , name ) ;
975
- if ( compilerHost . fileExists ( fullPath ) ) {
980
+ const fullPath = resolvePath ( host . getCurrentDirectory ( ) , name ) ;
981
+ if ( host . fileExists ( fullPath ) ) {
976
982
return fullPath as ResolvedConfigFileName ;
977
983
}
978
984
const fullPathWithTsconfig = combinePaths ( fullPath , "tsconfig.json" ) ;
979
- if ( compilerHost . fileExists ( fullPathWithTsconfig ) ) {
985
+ if ( host . fileExists ( fullPathWithTsconfig ) ) {
980
986
return fullPathWithTsconfig as ResolvedConfigFileName ;
981
987
}
982
988
buildHost . error ( Diagnostics . File_0_not_found , relName ( fullPath ) ) ;
@@ -1058,7 +1064,7 @@ namespace ts {
1058
1064
}
1059
1065
1060
1066
function relName ( path : string ) : string {
1061
- return convertToRelativePath ( path , compilerHost . getCurrentDirectory ( ) , f => compilerHost . getCanonicalFileName ( f ) ) ;
1067
+ return convertToRelativePath ( path , host . getCurrentDirectory ( ) , f => host . getCanonicalFileName ( f ) ) ;
1062
1068
}
1063
1069
1064
1070
function reportVerbose ( message : DiagnosticMessage , ...args : string [ ] ) {
@@ -1074,15 +1080,6 @@ namespace ts {
1074
1080
}
1075
1081
}
1076
1082
1077
- export interface UpToDateHost {
1078
- fileExists ( fileName : string ) : boolean ;
1079
- getModifiedTime ( fileName : string ) : Date | undefined ;
1080
- getUnchangedTime ?( fileName : string ) : Date | undefined ;
1081
- getLastStatus ?( fileName : string ) : UpToDateStatus | undefined ;
1082
- setLastStatus ?( fileName : string , status : UpToDateStatus ) : void ;
1083
- parseConfigFile ?( configFilePath : ResolvedConfigFileName ) : ParsedCommandLine | undefined ;
1084
- }
1085
-
1086
1083
export function getAllProjectOutputs ( project : ParsedCommandLine ) : ReadonlyArray < string > {
1087
1084
if ( project . options . outFile ) {
1088
1085
return getOutFileOutputs ( project ) ;
0 commit comments