@@ -148,7 +148,7 @@ namespace ts {
148
148
/**
149
149
* true if build info is emitted
150
150
*/
151
- emittedBuildInfo ? : boolean ;
151
+ buildInfoEmitPending : boolean ;
152
152
/**
153
153
* Already seen emitted files
154
154
*/
@@ -173,7 +173,7 @@ namespace ts {
173
173
const compilerOptions = newProgram . getCompilerOptions ( ) ;
174
174
state . compilerOptions = compilerOptions ;
175
175
// With --out or --outFile, any change affects all semantic diagnostics so no need to cache them
176
- if ( ! compilerOptions . outFile && ! compilerOptions . out ) {
176
+ if ( ! outFile ( compilerOptions ) ) {
177
177
state . semanticDiagnosticsPerFile = createMap < readonly Diagnostic [ ] > ( ) ;
178
178
}
179
179
state . changedFilesSet = createMap < true > ( ) ;
@@ -197,7 +197,7 @@ namespace ts {
197
197
if ( changedFilesSet ) {
198
198
copyEntries ( changedFilesSet , state . changedFilesSet ) ;
199
199
}
200
- if ( ! compilerOptions . outFile && ! compilerOptions . out && oldState ! . affectedFilesPendingEmit ) {
200
+ if ( ! outFile ( compilerOptions ) && oldState ! . affectedFilesPendingEmit ) {
201
201
state . affectedFilesPendingEmit = oldState ! . affectedFilesPendingEmit . slice ( ) ;
202
202
state . affectedFilesPendingEmitKind = cloneMapOrUndefined ( oldState ! . affectedFilesPendingEmitKind ) ;
203
203
state . affectedFilesPendingEmitIndex = oldState ! . affectedFilesPendingEmitIndex ;
@@ -250,14 +250,14 @@ namespace ts {
250
250
BuilderState . getAllFilesExcludingDefaultLibraryFile ( state , newProgram , /*firstSourceFile*/ undefined )
251
251
. forEach ( file => state . changedFilesSet . set ( file . resolvedPath , true ) ) ;
252
252
}
253
- else if ( oldCompilerOptions && compilerOptionsAffectEmit ( compilerOptions , oldCompilerOptions ) ) {
253
+ else if ( oldCompilerOptions && ! outFile ( compilerOptions ) && compilerOptionsAffectEmit ( compilerOptions , oldCompilerOptions ) ) {
254
254
// Add all files to affectedFilesPendingEmit since emit changed
255
255
newProgram . getSourceFiles ( ) . forEach ( f => addToAffectedFilesPendingEmit ( state , f . resolvedPath , BuilderFileEmit . Full ) ) ;
256
256
Debug . assert ( ! state . seenAffectedFiles || ! state . seenAffectedFiles . size ) ;
257
257
state . seenAffectedFiles = state . seenAffectedFiles || createMap < true > ( ) ;
258
258
}
259
259
260
- state . emittedBuildInfo = ! state . changedFilesSet . size && ! state . affectedFilesPendingEmit ;
260
+ state . buildInfoEmitPending = ! ! state . changedFilesSet . size ;
261
261
return state ;
262
262
}
263
263
@@ -374,7 +374,7 @@ namespace ts {
374
374
// so operations are performed directly on program, return program
375
375
const program = Debug . checkDefined ( state . program ) ;
376
376
const compilerOptions = program . getCompilerOptions ( ) ;
377
- if ( compilerOptions . outFile || compilerOptions . out ) {
377
+ if ( outFile ( compilerOptions ) ) {
378
378
Debug . assert ( ! state . semanticDiagnosticsPerFile ) ;
379
379
return program ;
380
380
}
@@ -611,7 +611,7 @@ namespace ts {
611
611
isBuildInfoEmit ?: boolean
612
612
) {
613
613
if ( isBuildInfoEmit ) {
614
- state . emittedBuildInfo = true ;
614
+ state . buildInfoEmitPending = false ;
615
615
}
616
616
else if ( affected === state . program ) {
617
617
state . changedFilesSet . clear ( ) ;
@@ -624,6 +624,7 @@ namespace ts {
624
624
}
625
625
if ( isPendingEmit ) {
626
626
state . affectedFilesPendingEmitIndex ! ++ ;
627
+ state . buildInfoEmitPending = true ;
627
628
}
628
629
else {
629
630
state . affectedFilesIndex ! ++ ;
@@ -688,19 +689,21 @@ namespace ts {
688
689
}
689
690
690
691
export type ProgramBuildInfoDiagnostic = string | [ string , readonly ReusableDiagnostic [ ] ] ;
692
+ export type ProgramBuilderInfoFilePendingEmit = [ string , BuilderFileEmit ] ;
691
693
export interface ProgramBuildInfo {
692
694
fileInfos : MapLike < BuilderState . FileInfo > ;
693
695
options : CompilerOptions ;
694
696
referencedMap ?: MapLike < string [ ] > ;
695
697
exportedModulesMap ?: MapLike < string [ ] > ;
696
698
semanticDiagnosticsPerFile ?: ProgramBuildInfoDiagnostic [ ] ;
699
+ affectedFilesPendingEmit ?: ProgramBuilderInfoFilePendingEmit [ ] ;
697
700
}
698
701
699
702
/**
700
703
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
701
704
*/
702
705
function getProgramBuildInfo ( state : Readonly < ReusableBuilderProgramState > , getCanonicalFileName : GetCanonicalFileName ) : ProgramBuildInfo | undefined {
703
- if ( state . compilerOptions . outFile || state . compilerOptions . out ) return undefined ;
706
+ if ( outFile ( state . compilerOptions ) ) return undefined ;
704
707
const currentDirectory = Debug . checkDefined ( state . program ) . getCurrentDirectory ( ) ;
705
708
const buildInfoDirectory = getDirectoryPath ( getNormalizedAbsolutePath ( getTsBuildInfoEmitOutputFilePath ( state . compilerOptions ) ! , currentDirectory ) ) ;
706
709
const fileInfos : MapLike < BuilderState . FileInfo > = { } ;
@@ -751,6 +754,17 @@ namespace ts {
751
754
result . semanticDiagnosticsPerFile = semanticDiagnosticsPerFile ;
752
755
}
753
756
757
+ if ( state . affectedFilesPendingEmit ) {
758
+ const affectedFilesPendingEmit : ProgramBuilderInfoFilePendingEmit [ ] = [ ] ;
759
+ const seenFiles = createMap < true > ( ) ;
760
+ for ( const path of state . affectedFilesPendingEmit . slice ( state . affectedFilesPendingEmitIndex ) . sort ( compareStringsCaseSensitive ) ) {
761
+ if ( addToSeen ( seenFiles , path ) ) {
762
+ affectedFilesPendingEmit . push ( [ relativeToBuildInfo ( path ) , state . affectedFilesPendingEmitKind ! . get ( path ) ! ] ) ;
763
+ }
764
+ }
765
+ result . affectedFilesPendingEmit = affectedFilesPendingEmit ;
766
+ }
767
+
754
768
return result ;
755
769
756
770
function relativeToBuildInfoEnsuringAbsolutePath ( path : string ) {
@@ -916,13 +930,23 @@ namespace ts {
916
930
else if ( kind === BuilderProgramKind . EmitAndSemanticDiagnosticsBuilderProgram ) {
917
931
( builderProgram as EmitAndSemanticDiagnosticsBuilderProgram ) . getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile ;
918
932
( builderProgram as EmitAndSemanticDiagnosticsBuilderProgram ) . emitNextAffectedFile = emitNextAffectedFile ;
933
+ builderProgram . emitBuildInfo = emitBuildInfo ;
919
934
}
920
935
else {
921
936
notImplemented ( ) ;
922
937
}
923
938
924
939
return builderProgram ;
925
940
941
+ function emitBuildInfo ( writeFile ?: WriteFileCallback , cancellationToken ?: CancellationToken ) : EmitResult {
942
+ if ( state . buildInfoEmitPending ) {
943
+ const result = Debug . checkDefined ( state . program ) . emitBuildInfo ( writeFile || maybeBind ( host , host . writeFile ) , cancellationToken ) ;
944
+ state . buildInfoEmitPending = false ;
945
+ return result ;
946
+ }
947
+ return emitSkippedWithNoDiagnostics ;
948
+ }
949
+
926
950
/**
927
951
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
928
952
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
@@ -933,10 +957,10 @@ namespace ts {
933
957
let emitKind = BuilderFileEmit . Full ;
934
958
let isPendingEmitFile = false ;
935
959
if ( ! affected ) {
936
- if ( ! state . compilerOptions . out && ! state . compilerOptions . outFile ) {
960
+ if ( ! outFile ( state . compilerOptions ) ) {
937
961
const pendingAffectedFile = getNextAffectedFilePendingEmit ( state ) ;
938
962
if ( ! pendingAffectedFile ) {
939
- if ( state . emittedBuildInfo ) {
963
+ if ( ! state . buildInfoEmitPending ) {
940
964
return undefined ;
941
965
}
942
966
@@ -993,7 +1017,7 @@ namespace ts {
993
1017
function emit ( targetSourceFile ?: SourceFile , writeFile ?: WriteFileCallback , cancellationToken ?: CancellationToken , emitOnlyDtsFiles ?: boolean , customTransformers ?: CustomTransformers ) : EmitResult {
994
1018
if ( kind === BuilderProgramKind . EmitAndSemanticDiagnosticsBuilderProgram ) {
995
1019
assertSourceFileOkWithoutNextAffectedCall ( state , targetSourceFile ) ;
996
- const result = handleNoEmitOptions ( builderProgram , targetSourceFile , cancellationToken ) ;
1020
+ const result = handleNoEmitOptions ( builderProgram , targetSourceFile , writeFile , cancellationToken ) ;
997
1021
if ( result ) return result ;
998
1022
if ( ! targetSourceFile ) {
999
1023
// Emit and report any errors we ran into.
@@ -1071,7 +1095,7 @@ namespace ts {
1071
1095
function getSemanticDiagnostics ( sourceFile ?: SourceFile , cancellationToken ?: CancellationToken ) : readonly Diagnostic [ ] {
1072
1096
assertSourceFileOkWithoutNextAffectedCall ( state , sourceFile ) ;
1073
1097
const compilerOptions = Debug . checkDefined ( state . program ) . getCompilerOptions ( ) ;
1074
- if ( compilerOptions . outFile || compilerOptions . out ) {
1098
+ if ( outFile ( compilerOptions ) ) {
1075
1099
Debug . assert ( ! state . semanticDiagnosticsPerFile ) ;
1076
1100
// We dont need to cache the diagnostics just return them from program
1077
1101
return Debug . checkDefined ( state . program ) . getSemanticDiagnostics ( sourceFile , cancellationToken ) ;
@@ -1142,7 +1166,10 @@ namespace ts {
1142
1166
referencedMap : getMapOfReferencedSet ( program . referencedMap , toPath ) ,
1143
1167
exportedModulesMap : getMapOfReferencedSet ( program . exportedModulesMap , toPath ) ,
1144
1168
semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => toPath ( isString ( value ) ? value : value [ 0 ] ) , value => isString ( value ) ? emptyArray : value [ 1 ] ) ,
1145
- hasReusableDiagnostic : true
1169
+ hasReusableDiagnostic : true ,
1170
+ affectedFilesPendingEmit : map ( program . affectedFilesPendingEmit , value => toPath ( value [ 0 ] ) ) ,
1171
+ affectedFilesPendingEmitKind : program . affectedFilesPendingEmit && arrayToMap ( program . affectedFilesPendingEmit , value => toPath ( value [ 0 ] ) , value => value [ 1 ] ) ,
1172
+ affectedFilesPendingEmitIndex : program . affectedFilesPendingEmit && 0 ,
1146
1173
} ;
1147
1174
return {
1148
1175
getState : ( ) => state ,
@@ -1165,6 +1192,7 @@ namespace ts {
1165
1192
getCurrentDirectory : notImplemented ,
1166
1193
emitNextAffectedFile : notImplemented ,
1167
1194
getSemanticDiagnosticsOfNextAffectedFile : notImplemented ,
1195
+ emitBuildInfo : notImplemented ,
1168
1196
close : noop ,
1169
1197
} ;
1170
1198
@@ -1195,6 +1223,7 @@ namespace ts {
1195
1223
getDeclarationDiagnostics : ( sourceFile , cancellationToken ) => getProgram ( ) . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ,
1196
1224
getSemanticDiagnostics : ( sourceFile , cancellationToken ) => getProgram ( ) . getSemanticDiagnostics ( sourceFile , cancellationToken ) ,
1197
1225
emit : ( sourceFile , writeFile , cancellationToken , emitOnlyDts , customTransformers ) => getProgram ( ) . emit ( sourceFile , writeFile , cancellationToken , emitOnlyDts , customTransformers ) ,
1226
+ emitBuildInfo : ( writeFile , cancellationToken ) => getProgram ( ) . emitBuildInfo ( writeFile , cancellationToken ) ,
1198
1227
getAllDependencies : notImplemented ,
1199
1228
getCurrentDirectory : ( ) => getProgram ( ) . getCurrentDirectory ( ) ,
1200
1229
close : noop ,
0 commit comments