@@ -283,14 +283,30 @@ namespace ts {
283
283
/*@internal */ buildNextInvalidatedProject ( ) : void ;
284
284
}
285
285
286
- interface InvalidatedProject {
286
+ const enum InvalidatedProjectKind {
287
+ BuildProject ,
288
+ UpdateBundle ,
289
+ UpdateOutputFileStamps
290
+ }
291
+
292
+ interface UpdateOutputFileStampsProject {
293
+ readonly kind : InvalidatedProjectKind . UpdateOutputFileStamps ;
294
+ readonly project : ResolvedConfigFileName ;
295
+ readonly projectPath : ResolvedConfigFilePath ;
296
+ readonly config : ParsedCommandLine ;
297
+ }
298
+
299
+ interface BuildOrUpdateBundleProject {
300
+ readonly kind : InvalidatedProjectKind . BuildProject | InvalidatedProjectKind . UpdateBundle ;
287
301
readonly project : ResolvedConfigFileName ;
288
302
readonly projectPath : ResolvedConfigFilePath ;
289
- readonly reloadLevel : ConfigFileProgramReloadLevel ;
290
303
readonly projectIndex : number ;
304
+ readonly config : ParsedCommandLine ;
291
305
readonly buildOrder : readonly ResolvedConfigFileName [ ] ;
292
306
}
293
307
308
+ type InvalidatedProject = UpdateOutputFileStampsProject | BuildOrUpdateBundleProject ;
309
+
294
310
/**
295
311
* Create a function that reports watch status by writing to the system and handles the formating of the diagnostic
296
312
*/
@@ -663,15 +679,90 @@ namespace ts {
663
679
}
664
680
665
681
function getNextInvalidatedProject ( state : SolutionBuilderState , buildOrder : readonly ResolvedConfigFileName [ ] ) : InvalidatedProject | undefined {
666
- return state . projectPendingBuild . size ?
667
- forEach ( buildOrder , ( project , projectIndex ) => {
668
- const projectPath = toResolvedConfigFilePath ( state , project ) ;
669
- const reloadLevel = state . projectPendingBuild . get ( projectPath ) ;
670
- if ( reloadLevel !== undefined ) {
671
- return { project, projectPath, reloadLevel, projectIndex, buildOrder } ;
682
+ if ( ! state . projectPendingBuild . size ) return undefined ;
683
+
684
+ const { options, projectPendingBuild } = state ;
685
+ for ( let projectIndex = 0 ; projectIndex < buildOrder . length ; projectIndex ++ ) {
686
+ const project = buildOrder [ projectIndex ] ;
687
+ const projectPath = toResolvedConfigFilePath ( state , project ) ;
688
+ const reloadLevel = state . projectPendingBuild . get ( projectPath ) ;
689
+ if ( reloadLevel === undefined ) continue ;
690
+
691
+ const config = parseConfigFile ( state , project , projectPath ) ;
692
+ if ( ! config ) {
693
+ reportParseConfigFileDiagnostic ( state , projectPath ) ;
694
+ projectPendingBuild . delete ( projectPath ) ;
695
+ continue ;
696
+ }
697
+
698
+ if ( reloadLevel === ConfigFileProgramReloadLevel . Full ) {
699
+ watchConfigFile ( state , project , projectPath ) ;
700
+ watchWildCardDirectories ( state , project , projectPath , config ) ;
701
+ watchInputFiles ( state , project , projectPath , config ) ;
702
+ }
703
+ else if ( reloadLevel === ConfigFileProgramReloadLevel . Partial ) {
704
+ // Update file names
705
+ const result = getFileNamesFromConfigSpecs ( config . configFileSpecs ! , getDirectoryPath ( project ) , config . options , state . parseConfigFileHost ) ;
706
+ updateErrorForNoInputFiles ( result , project , config . configFileSpecs ! , config . errors , canJsonReportNoInutFiles ( config . raw ) ) ;
707
+ config . fileNames = result . fileNames ;
708
+ watchInputFiles ( state , project , projectPath , config ) ;
709
+ }
710
+
711
+ const status = getUpToDateStatus ( state , config , projectPath ) ;
712
+ verboseReportProjectStatus ( state , project , status ) ;
713
+ if ( ! options . force ) {
714
+ if ( status . type === UpToDateStatusType . UpToDate ) {
715
+ reportAndStoreErrors ( state , projectPath , config . errors ) ;
716
+ projectPendingBuild . delete ( projectPath ) ;
717
+ // Up to date, skip
718
+ if ( options . dry ) {
719
+ // In a dry build, inform the user of this fact
720
+ reportStatus ( state , Diagnostics . Project_0_is_up_to_date , project ) ;
721
+ }
722
+ continue ;
672
723
}
673
- } ) :
674
- undefined ;
724
+
725
+ if ( status . type === UpToDateStatusType . UpToDateWithUpstreamTypes ) {
726
+ reportAndStoreErrors ( state , projectPath , config . errors ) ;
727
+ return {
728
+ kind : InvalidatedProjectKind . UpdateOutputFileStamps ,
729
+ project,
730
+ projectPath,
731
+ config
732
+ } ;
733
+
734
+ continue ;
735
+ }
736
+ }
737
+
738
+ if ( status . type === UpToDateStatusType . UpstreamBlocked ) {
739
+ reportAndStoreErrors ( state , projectPath , config . errors ) ;
740
+ projectPendingBuild . delete ( projectPath ) ;
741
+ if ( options . verbose ) reportStatus ( state , Diagnostics . Skipping_build_of_project_0_because_its_dependency_1_has_errors , project , status . upstreamProjectName ) ;
742
+ continue ;
743
+ }
744
+
745
+ if ( status . type === UpToDateStatusType . ContainerOnly ) {
746
+ reportAndStoreErrors ( state , projectPath , config . errors ) ;
747
+ projectPendingBuild . delete ( projectPath ) ;
748
+ // Do nothing
749
+ continue ;
750
+ }
751
+
752
+
753
+ return {
754
+ kind : needsBuild ( state , status , config ) ?
755
+ InvalidatedProjectKind . BuildProject :
756
+ InvalidatedProjectKind . UpdateBundle ,
757
+ project,
758
+ projectPath,
759
+ projectIndex,
760
+ config,
761
+ buildOrder
762
+ } ;
763
+ }
764
+
765
+ return undefined ;
675
766
}
676
767
677
768
function listEmittedFile ( { writeFileName } : SolutionBuilderState , proj : ParsedCommandLine , file : string ) {
@@ -714,62 +805,70 @@ namespace ts {
714
805
return errorFlags ;
715
806
}
716
807
717
- function buildSingleProject ( state : SolutionBuilderState , proj : ResolvedConfigFileName , resolvedPath : ResolvedConfigFilePath , cancellationToken : CancellationToken | undefined ) : BuildResultFlags {
808
+ function updateModuleResolutionCache (
809
+ state : SolutionBuilderState ,
810
+ proj : ResolvedConfigFileName ,
811
+ config : ParsedCommandLine
812
+ ) {
813
+ if ( ! state . moduleResolutionCache ) return ;
814
+
815
+ // Update module resolution cache if needed
816
+ const { moduleResolutionCache } = state ;
817
+ const projPath = toPath ( state , proj ) ;
818
+ if ( moduleResolutionCache . directoryToModuleNameMap . redirectsMap . size === 0 ) {
819
+ // The own map will be for projectCompilerOptions
820
+ Debug . assert ( moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . size === 0 ) ;
821
+ moduleResolutionCache . directoryToModuleNameMap . redirectsMap . set ( projPath , moduleResolutionCache . directoryToModuleNameMap . ownMap ) ;
822
+ moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . set ( projPath , moduleResolutionCache . moduleNameToDirectoryMap . ownMap ) ;
823
+ }
824
+ else {
825
+ // Set correct own map
826
+ Debug . assert ( moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . size > 0 ) ;
827
+
828
+ const ref : ResolvedProjectReference = {
829
+ sourceFile : config . options . configFile ! ,
830
+ commandLine : config
831
+ } ;
832
+ moduleResolutionCache . directoryToModuleNameMap . setOwnMap ( moduleResolutionCache . directoryToModuleNameMap . getOrCreateMapOfCacheRedirects ( ref ) ) ;
833
+ moduleResolutionCache . moduleNameToDirectoryMap . setOwnMap ( moduleResolutionCache . moduleNameToDirectoryMap . getOrCreateMapOfCacheRedirects ( ref ) ) ;
834
+ }
835
+ moduleResolutionCache . directoryToModuleNameMap . setOwnOptions ( config . options ) ;
836
+ moduleResolutionCache . moduleNameToDirectoryMap . setOwnOptions ( config . options ) ;
837
+ }
838
+
839
+ function buildSingleProject (
840
+ state : SolutionBuilderState ,
841
+ proj : ResolvedConfigFileName ,
842
+ resolvedPath : ResolvedConfigFilePath ,
843
+ config : ParsedCommandLine ,
844
+ cancellationToken : CancellationToken | undefined
845
+ ) : BuildResultFlags {
718
846
if ( state . options . dry ) {
719
847
reportStatus ( state , Diagnostics . A_non_dry_build_would_build_project_0 , proj ) ;
720
848
return BuildResultFlags . Success ;
721
849
}
722
850
723
851
if ( state . options . verbose ) reportStatus ( state , Diagnostics . Building_project_0 , proj ) ;
724
852
725
- const { host, projectStatus, diagnostics, compilerHost, moduleResolutionCache, } = state ;
726
- const configFile = parseConfigFile ( state , proj , resolvedPath ) ;
727
- if ( ! configFile ) {
728
- // Failed to read the config file
729
- reportParseConfigFileDiagnostic ( state , resolvedPath ) ;
730
- projectStatus . set ( resolvedPath , { type : UpToDateStatusType . Unbuildable , reason : "Config file errors" } ) ;
731
- return BuildResultFlags . ConfigFileErrors ;
732
- }
733
-
734
- if ( configFile . fileNames . length === 0 ) {
735
- reportAndStoreErrors ( state , resolvedPath , configFile . errors ) ;
853
+ if ( config . fileNames . length === 0 ) {
854
+ reportAndStoreErrors ( state , resolvedPath , config . errors ) ;
736
855
// Nothing to build - must be a solution file, basically
737
856
return BuildResultFlags . None ;
738
857
}
739
858
740
- state . projectCompilerOptions = configFile . options ;
859
+ const { host, projectStatus, diagnostics, compilerHost } = state ;
860
+ state . projectCompilerOptions = config . options ;
741
861
// Update module resolution cache if needed
742
- if ( moduleResolutionCache ) {
743
- const projPath = toPath ( state , proj ) ;
744
- if ( moduleResolutionCache . directoryToModuleNameMap . redirectsMap . size === 0 ) {
745
- // The own map will be for projectCompilerOptions
746
- Debug . assert ( moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . size === 0 ) ;
747
- moduleResolutionCache . directoryToModuleNameMap . redirectsMap . set ( projPath , moduleResolutionCache . directoryToModuleNameMap . ownMap ) ;
748
- moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . set ( projPath , moduleResolutionCache . moduleNameToDirectoryMap . ownMap ) ;
749
- }
750
- else {
751
- // Set correct own map
752
- Debug . assert ( moduleResolutionCache . moduleNameToDirectoryMap . redirectsMap . size > 0 ) ;
753
-
754
- const ref : ResolvedProjectReference = {
755
- sourceFile : configFile . options . configFile ! ,
756
- commandLine : configFile
757
- } ;
758
- moduleResolutionCache . directoryToModuleNameMap . setOwnMap ( moduleResolutionCache . directoryToModuleNameMap . getOrCreateMapOfCacheRedirects ( ref ) ) ;
759
- moduleResolutionCache . moduleNameToDirectoryMap . setOwnMap ( moduleResolutionCache . moduleNameToDirectoryMap . getOrCreateMapOfCacheRedirects ( ref ) ) ;
760
- }
761
- moduleResolutionCache . directoryToModuleNameMap . setOwnOptions ( configFile . options ) ;
762
- moduleResolutionCache . moduleNameToDirectoryMap . setOwnOptions ( configFile . options ) ;
763
- }
862
+ updateModuleResolutionCache ( state , proj , config ) ;
764
863
765
864
// Create program
766
865
const program = host . createProgram (
767
- configFile . fileNames ,
768
- configFile . options ,
866
+ config . fileNames ,
867
+ config . options ,
769
868
compilerHost ,
770
- getOldProgram ( state , resolvedPath , configFile ) ,
771
- configFile . errors ,
772
- configFile . projectReferences
869
+ getOldProgram ( state , resolvedPath , config ) ,
870
+ config . errors ,
871
+ config . projectReferences
773
872
) ;
774
873
775
874
// Don't emit anything in the presence of syntactic errors or options diagnostics
@@ -867,24 +966,30 @@ namespace ts {
867
966
}
868
967
869
968
if ( state . writeFileName ) {
870
- emittedOutputs . forEach ( name => listEmittedFile ( state , configFile , name ) ) ;
969
+ emittedOutputs . forEach ( name => listEmittedFile ( state , config , name ) ) ;
871
970
listFiles ( program , state . writeFileName ) ;
872
971
}
873
972
874
973
// Update time stamps for rest of the outputs
875
- newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker ( state , configFile , newestDeclarationFileContentChangedTime , Diagnostics . Updating_unchanged_output_timestamps_of_project_0 , emittedOutputs ) ;
974
+ newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker ( state , config , newestDeclarationFileContentChangedTime , Diagnostics . Updating_unchanged_output_timestamps_of_project_0 , emittedOutputs ) ;
876
975
diagnostics . delete ( resolvedPath ) ;
877
976
projectStatus . set ( resolvedPath , {
878
977
type : UpToDateStatusType . UpToDate ,
879
978
newestDeclarationFileContentChangedTime : anyDtsChanged ? maximumDate : newestDeclarationFileContentChangedTime ,
880
- oldestOutputFileName : outputFiles . length ? outputFiles [ 0 ] . name : getFirstProjectOutput ( configFile , ! host . useCaseSensitiveFileNames ( ) )
979
+ oldestOutputFileName : outputFiles . length ? outputFiles [ 0 ] . name : getFirstProjectOutput ( config , ! host . useCaseSensitiveFileNames ( ) )
881
980
} ) ;
882
981
afterProgramCreate ( state , resolvedPath , program ) ;
883
982
state . projectCompilerOptions = state . baseCompilerOptions ;
884
983
return resultFlags ;
885
984
}
886
985
887
- function updateBundle ( state : SolutionBuilderState , proj : ResolvedConfigFileName , resolvedPath : ResolvedConfigFilePath , cancellationToken : CancellationToken | undefined ) : BuildResultFlags {
986
+ function updateBundle (
987
+ state : SolutionBuilderState ,
988
+ proj : ResolvedConfigFileName ,
989
+ resolvedPath : ResolvedConfigFilePath ,
990
+ config : ParsedCommandLine ,
991
+ cancellationToken : CancellationToken | undefined
992
+ ) : BuildResultFlags {
888
993
if ( state . options . dry ) {
889
994
reportStatus ( state , Diagnostics . A_non_dry_build_would_update_output_of_project_0 , proj ) ;
890
995
return BuildResultFlags . Success ;
@@ -894,7 +999,6 @@ namespace ts {
894
999
895
1000
// Update js, and source map
896
1001
const { projectStatus, diagnostics, compilerHost } = state ;
897
- const config = Debug . assertDefined ( parseConfigFile ( state , proj , resolvedPath ) ) ;
898
1002
state . projectCompilerOptions = config . options ;
899
1003
const outputFiles = emitUsingBuildInfo (
900
1004
config ,
@@ -905,7 +1009,7 @@ namespace ts {
905
1009
} ) ;
906
1010
if ( isString ( outputFiles ) ) {
907
1011
reportStatus ( state , Diagnostics . Cannot_update_output_of_project_0_because_there_was_error_reading_file_1 , proj , relName ( state , outputFiles ) ) ;
908
- return buildSingleProject ( state , proj , resolvedPath , cancellationToken ) ;
1012
+ return buildSingleProject ( state , proj , resolvedPath , config , cancellationToken ) ;
909
1013
}
910
1014
911
1015
// Actual Emit
@@ -1210,68 +1314,24 @@ namespace ts {
1210
1314
! isIncrementalCompilation ( config . options ) ;
1211
1315
}
1212
1316
1213
- function buildInvalidatedProject ( state : SolutionBuilderState , { project, projectPath, reloadLevel, projectIndex, buildOrder } : InvalidatedProject , cancellationToken ?: CancellationToken ) {
1214
- const { options, projectPendingBuild } = state ;
1215
- const config = parseConfigFile ( state , project , projectPath ) ;
1216
- if ( ! config ) {
1217
- reportParseConfigFileDiagnostic ( state , projectPath ) ;
1218
- projectPendingBuild . delete ( projectPath ) ;
1219
- return ;
1220
- }
1221
-
1222
- if ( reloadLevel === ConfigFileProgramReloadLevel . Full ) {
1223
- watchConfigFile ( state , project , projectPath ) ;
1224
- watchWildCardDirectories ( state , project , projectPath , config ) ;
1225
- watchInputFiles ( state , project , projectPath , config ) ;
1226
- }
1227
- else if ( reloadLevel === ConfigFileProgramReloadLevel . Partial ) {
1228
- // Update file names
1229
- const result = getFileNamesFromConfigSpecs ( config . configFileSpecs ! , getDirectoryPath ( project ) , config . options , state . parseConfigFileHost ) ;
1230
- updateErrorForNoInputFiles ( result , project , config . configFileSpecs ! , config . errors , canJsonReportNoInutFiles ( config . raw ) ) ;
1231
- config . fileNames = result . fileNames ;
1232
- watchInputFiles ( state , project , projectPath , config ) ;
1233
- }
1234
-
1235
- const status = getUpToDateStatus ( state , config , projectPath ) ;
1236
- verboseReportProjectStatus ( state , project , status ) ;
1237
- if ( ! options . force ) {
1238
- if ( status . type === UpToDateStatusType . UpToDate ) {
1239
- reportAndStoreErrors ( state , projectPath , config . errors ) ;
1240
- projectPendingBuild . delete ( projectPath ) ;
1241
- // Up to date, skip
1242
- if ( options . dry ) {
1243
- // In a dry build, inform the user of this fact
1244
- reportStatus ( state , Diagnostics . Project_0_is_up_to_date , project ) ;
1245
- }
1246
- return ;
1247
- }
1248
-
1249
- if ( status . type === UpToDateStatusType . UpToDateWithUpstreamTypes ) {
1250
- reportAndStoreErrors ( state , projectPath , config . errors ) ;
1251
- projectPendingBuild . delete ( projectPath ) ;
1252
- // Fake that files have been built by updating output file stamps
1253
- updateOutputTimestamps ( state , config , projectPath ) ;
1254
- return ;
1255
- }
1256
- }
1257
-
1258
- if ( status . type === UpToDateStatusType . UpstreamBlocked ) {
1259
- reportAndStoreErrors ( state , projectPath , config . errors ) ;
1260
- projectPendingBuild . delete ( projectPath ) ;
1261
- if ( options . verbose ) reportStatus ( state , Diagnostics . Skipping_build_of_project_0_because_its_dependency_1_has_errors , project , status . upstreamProjectName ) ;
1262
- return ;
1263
- }
1264
-
1265
- if ( status . type === UpToDateStatusType . ContainerOnly ) {
1266
- reportAndStoreErrors ( state , projectPath , config . errors ) ;
1317
+ function buildInvalidatedProject (
1318
+ state : SolutionBuilderState ,
1319
+ invalidatedProject : InvalidatedProject ,
1320
+ cancellationToken ?: CancellationToken
1321
+ ) {
1322
+ const { projectPendingBuild } = state ;
1323
+ if ( invalidatedProject . kind === InvalidatedProjectKind . UpdateOutputFileStamps ) {
1324
+ // Fake that files have been built by updating output file stamps
1325
+ const { projectPath, config } = invalidatedProject ;
1326
+ updateOutputTimestamps ( state , config , projectPath ) ;
1267
1327
projectPendingBuild . delete ( projectPath ) ;
1268
- // Do nothing
1269
1328
return ;
1270
1329
}
1271
1330
1272
- const buildResult = needsBuild ( state , status , config ) ?
1273
- buildSingleProject ( state , project , projectPath , cancellationToken ) : // Actual build
1274
- updateBundle ( state , project , projectPath , cancellationToken ) ; // Fake that files have been built by manipulating prepend and existing output
1331
+ const { kind, project, projectPath, projectIndex, config, buildOrder } = invalidatedProject ;
1332
+ const buildResult = kind === InvalidatedProjectKind . BuildProject ?
1333
+ buildSingleProject ( state , project , projectPath , config , cancellationToken ) : // Actual build
1334
+ updateBundle ( state , project , projectPath , config , cancellationToken ) ; // Fake that files have been built by manipulating prepend and existing output
1275
1335
projectPendingBuild . delete ( projectPath ) ;
1276
1336
// Only composite projects can be referenced by other projects
1277
1337
if ( ! ( buildResult & BuildResultFlags . AnyErrors ) && config . options . composite ) {
@@ -1467,12 +1527,11 @@ namespace ts {
1467
1527
if ( state . watch && ! state . timerToBuildInvalidatedProject ) {
1468
1528
scheduleBuildInvalidatedProject ( state ) ;
1469
1529
}
1470
- }
1471
- else {
1472
- disableCache ( state ) ;
1473
- reportErrorSummary ( state ) ;
1530
+ return ;
1474
1531
}
1475
1532
}
1533
+ disableCache ( state ) ;
1534
+ reportErrorSummary ( state ) ;
1476
1535
}
1477
1536
1478
1537
function watchConfigFile ( state : SolutionBuilderState , resolved : ResolvedConfigFileName , resolvedPath : ResolvedConfigFilePath ) {
0 commit comments