@@ -60,6 +60,10 @@ namespace ts {
6060 * Files pending to be emitted
6161 */
6262 affectedFilesPendingEmit ?: ReadonlyArray < Path > | undefined ;
63+ /**
64+ * Files pending to be emitted kind.
65+ */
66+ affectedFilesPendingEmitKind ?: ReadonlyMap < BuilderFileEmit > | undefined ;
6367 /**
6468 * Current index to retrieve pending affected file
6569 */
@@ -70,6 +74,11 @@ namespace ts {
7074 hasReusableDiagnostic ?: true ;
7175 }
7276
77+ export const enum BuilderFileEmit {
78+ DtsOnly ,
79+ Full
80+ }
81+
7382 /**
7483 * State to store the changed files, affected files and cache semantic diagnostics
7584 */
@@ -127,7 +136,11 @@ namespace ts {
127136 /**
128137 * Files pending to be emitted
129138 */
130- affectedFilesPendingEmit : ReadonlyArray < Path > | undefined ;
139+ affectedFilesPendingEmit : Path [ ] | undefined ;
140+ /**
141+ * Files pending to be emitted kind.
142+ */
143+ affectedFilesPendingEmitKind : Map < BuilderFileEmit > | undefined ;
131144 /**
132145 * Current index to retrieve pending affected file
133146 */
@@ -139,7 +152,7 @@ namespace ts {
139152 /**
140153 * Already seen emitted files
141154 */
142- seenEmittedFiles : Map < true > | undefined ;
155+ seenEmittedFiles : Map < BuilderFileEmit > | undefined ;
143156 /**
144157 * true if program has been emitted
145158 */
@@ -186,7 +199,8 @@ namespace ts {
186199 copyEntries ( changedFilesSet , state . changedFilesSet ) ;
187200 }
188201 if ( ! compilerOptions . outFile && ! compilerOptions . out && oldState ! . affectedFilesPendingEmit ) {
189- state . affectedFilesPendingEmit = oldState ! . affectedFilesPendingEmit ;
202+ state . affectedFilesPendingEmit = oldState ! . affectedFilesPendingEmit . slice ( ) ;
203+ state . affectedFilesPendingEmitKind = cloneMapOrUndefined ( oldState ! . affectedFilesPendingEmitKind ) ;
190204 state . affectedFilesPendingEmitIndex = oldState ! . affectedFilesPendingEmitIndex ;
191205 }
192206 }
@@ -233,7 +247,7 @@ namespace ts {
233247
234248 if ( oldCompilerOptions && compilerOptionsAffectEmit ( compilerOptions , oldCompilerOptions ) ) {
235249 // Add all files to affectedFilesPendingEmit since emit changed
236- addToAffectedFilesPendingEmit ( state , newProgram . getSourceFiles ( ) . map ( f => f . path ) ) ;
250+ newProgram . getSourceFiles ( ) . forEach ( f => addToAffectedFilesPendingEmit ( state , f . path , BuilderFileEmit . Full ) ) ;
237251 Debug . assert ( state . seenAffectedFiles === undefined ) ;
238252 state . seenAffectedFiles = createMap < true > ( ) ;
239253 }
@@ -295,7 +309,8 @@ namespace ts {
295309 newState . semanticDiagnosticsFromOldState = cloneMapOrUndefined ( state . semanticDiagnosticsFromOldState ) ;
296310 newState . program = state . program ;
297311 newState . compilerOptions = state . compilerOptions ;
298- newState . affectedFilesPendingEmit = state . affectedFilesPendingEmit ;
312+ newState . affectedFilesPendingEmit = state . affectedFilesPendingEmit && state . affectedFilesPendingEmit . slice ( ) ;
313+ newState . affectedFilesPendingEmitKind = cloneMapOrUndefined ( state . affectedFilesPendingEmitKind ) ;
299314 newState . affectedFilesPendingEmitIndex = state . affectedFilesPendingEmitIndex ;
300315 newState . seenEmittedFiles = cloneMapOrUndefined ( state . seenEmittedFiles ) ;
301316 newState . programEmitComplete = state . programEmitComplete ;
@@ -373,19 +388,24 @@ namespace ts {
373388 /**
374389 * Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
375390 */
376- function getNextAffectedFilePendingEmit ( state : BuilderProgramState ) : SourceFile | undefined {
391+ function getNextAffectedFilePendingEmit ( state : BuilderProgramState ) {
377392 const { affectedFilesPendingEmit } = state ;
378393 if ( affectedFilesPendingEmit ) {
379394 const seenEmittedFiles = state . seenEmittedFiles || ( state . seenEmittedFiles = createMap ( ) ) ;
380395 for ( let i = state . affectedFilesPendingEmitIndex ! ; i < affectedFilesPendingEmit . length ; i ++ ) {
381396 const affectedFile = Debug . assertDefined ( state . program ) . getSourceFileByPath ( affectedFilesPendingEmit [ i ] ) ;
382- if ( affectedFile && ! seenEmittedFiles . has ( affectedFile . path ) ) {
383- // emit this file
384- state . affectedFilesPendingEmitIndex = i ;
385- return affectedFile ;
397+ if ( affectedFile ) {
398+ const seenKind = seenEmittedFiles . get ( affectedFile . path ) ;
399+ const emitKind = Debug . assertDefined ( Debug . assertDefined ( state . affectedFilesPendingEmitKind ) . get ( affectedFile . path ) ) ;
400+ if ( seenKind === undefined || seenKind < emitKind ) {
401+ // emit this file
402+ state . affectedFilesPendingEmitIndex = i ;
403+ return { affectedFile, emitKind } ;
404+ }
386405 }
387406 }
388407 state . affectedFilesPendingEmit = undefined ;
408+ state . affectedFilesPendingEmitKind = undefined ;
389409 state . affectedFilesPendingEmitIndex = undefined ;
390410 }
391411 return undefined ;
@@ -442,7 +462,7 @@ namespace ts {
442462 ) ;
443463 // If not dts emit, nothing more to do
444464 if ( getEmitDeclarations ( state . compilerOptions ) ) {
445- addToAffectedFilesPendingEmit ( state , [ path ] ) ;
465+ addToAffectedFilesPendingEmit ( state , path , BuilderFileEmit . DtsOnly ) ;
446466 }
447467 }
448468 }
@@ -548,7 +568,13 @@ namespace ts {
548568 * This is called after completing operation on the next affected file.
549569 * The operations here are postponed to ensure that cancellation during the iteration is handled correctly
550570 */
551- function doneWithAffectedFile ( state : BuilderProgramState , affected : SourceFile | Program , isPendingEmit ?: boolean , isBuildInfoEmit ?: boolean , isEmitResult ?: boolean ) {
571+ function doneWithAffectedFile (
572+ state : BuilderProgramState ,
573+ affected : SourceFile | Program ,
574+ emitKind ?: BuilderFileEmit ,
575+ isPendingEmit ?: boolean ,
576+ isBuildInfoEmit ?: boolean
577+ ) {
552578 if ( isBuildInfoEmit ) {
553579 state . emittedBuildInfo = true ;
554580 }
@@ -558,8 +584,8 @@ namespace ts {
558584 }
559585 else {
560586 state . seenAffectedFiles ! . set ( ( affected as SourceFile ) . path , true ) ;
561- if ( isEmitResult ) {
562- ( state . seenEmittedFiles || ( state . seenEmittedFiles = createMap ( ) ) ) . set ( ( affected as SourceFile ) . path , true ) ;
587+ if ( emitKind !== undefined ) {
588+ ( state . seenEmittedFiles || ( state . seenEmittedFiles = createMap ( ) ) ) . set ( ( affected as SourceFile ) . path , emitKind ) ;
563589 }
564590 if ( isPendingEmit ) {
565591 state . affectedFilesPendingEmitIndex ! ++ ;
@@ -573,16 +599,23 @@ namespace ts {
573599 /**
574600 * Returns the result with affected file
575601 */
576- function toAffectedFileResult < T > ( state : BuilderProgramState , result : T , affected : SourceFile | Program , isPendingEmit ?: boolean , isBuildInfoEmit ?: boolean ) : AffectedFileResult < T > {
577- doneWithAffectedFile ( state , affected , isPendingEmit , isBuildInfoEmit ) ;
602+ function toAffectedFileResult < T > ( state : BuilderProgramState , result : T , affected : SourceFile | Program ) : AffectedFileResult < T > {
603+ doneWithAffectedFile ( state , affected ) ;
578604 return { result, affected } ;
579605 }
580606
581607 /**
582608 * Returns the result with affected file
583609 */
584- function toAffectedFileEmitResult ( state : BuilderProgramState , result : EmitResult , affected : SourceFile | Program , isPendingEmit ?: boolean , isBuildInfoEmit ?: boolean ) : AffectedFileResult < EmitResult > {
585- doneWithAffectedFile ( state , affected , isPendingEmit , isBuildInfoEmit , /*isEmitResult*/ true ) ;
610+ function toAffectedFileEmitResult (
611+ state : BuilderProgramState ,
612+ result : EmitResult ,
613+ affected : SourceFile | Program ,
614+ emitKind : BuilderFileEmit ,
615+ isPendingEmit ?: boolean ,
616+ isBuildInfoEmit ?: boolean
617+ ) : AffectedFileResult < EmitResult > {
618+ doneWithAffectedFile ( state , affected , emitKind , isPendingEmit , isBuildInfoEmit ) ;
586619 return { result, affected } ;
587620 }
588621
@@ -849,11 +882,12 @@ namespace ts {
849882 */
850883 function emitNextAffectedFile ( writeFile ?: WriteFileCallback , cancellationToken ?: CancellationToken , emitOnlyDtsFiles ?: boolean , customTransformers ?: CustomTransformers ) : AffectedFileResult < EmitResult > {
851884 let affected = getNextAffectedFile ( state , cancellationToken , computeHash ) ;
885+ let emitKind = BuilderFileEmit . Full ;
852886 let isPendingEmitFile = false ;
853887 if ( ! affected ) {
854888 if ( ! state . compilerOptions . out && ! state . compilerOptions . outFile ) {
855- affected = getNextAffectedFilePendingEmit ( state ) ;
856- if ( ! affected ) {
889+ const pendingAffectedFile = getNextAffectedFilePendingEmit ( state ) ;
890+ if ( ! pendingAffectedFile ) {
857891 if ( state . emittedBuildInfo ) {
858892 return undefined ;
859893 }
@@ -865,10 +899,12 @@ namespace ts {
865899 // Otherwise just affected file
866900 affected . emitBuildInfo ( writeFile || maybeBind ( host , host . writeFile ) , cancellationToken ) ,
867901 affected ,
902+ /*emitKind*/ BuilderFileEmit . Full ,
868903 /*isPendingEmitFile*/ false ,
869904 /*isBuildInfoEmit*/ true
870905 ) ;
871906 }
907+ ( { affectedFile : affected , emitKind } = pendingAffectedFile ) ;
872908 isPendingEmitFile = true ;
873909 }
874910 else {
@@ -886,10 +922,17 @@ namespace ts {
886922 state ,
887923 // When whole program is affected, do emit only once (eg when --out or --outFile is specified)
888924 // Otherwise just affected file
889- Debug . assertDefined ( state . program ) . emit ( affected === state . program ? undefined : affected as SourceFile , writeFile || maybeBind ( host , host . writeFile ) , cancellationToken , emitOnlyDtsFiles , customTransformers ) ,
925+ Debug . assertDefined ( state . program ) . emit (
926+ affected === state . program ? undefined : affected as SourceFile ,
927+ writeFile || maybeBind ( host , host . writeFile ) ,
928+ cancellationToken ,
929+ emitOnlyDtsFiles || emitKind === BuilderFileEmit . DtsOnly ,
930+ customTransformers
931+ ) ,
890932 affected ,
933+ emitKind ,
891934 isPendingEmitFile ,
892- ) ;
935+ ) ;
893936 }
894937
895938 /**
@@ -953,7 +996,7 @@ namespace ts {
953996
954997 // Add file to affected file pending emit to handle for later emit time
955998 if ( kind === BuilderProgramKind . EmitAndSemanticDiagnosticsBuilderProgram ) {
956- addToAffectedFilesPendingEmit ( state , [ ( affected as SourceFile ) . path ] ) ;
999+ addToAffectedFilesPendingEmit ( state , ( affected as SourceFile ) . path , BuilderFileEmit . Full ) ;
9571000 }
9581001
9591002 // Get diagnostics for the affected file if its not ignored
@@ -1006,8 +1049,14 @@ namespace ts {
10061049 }
10071050 }
10081051
1009- function addToAffectedFilesPendingEmit ( state : BuilderProgramState , affectedFilesPendingEmit : readonly Path [ ] ) {
1010- state . affectedFilesPendingEmit = concatenate ( state . affectedFilesPendingEmit , affectedFilesPendingEmit ) ;
1052+ function addToAffectedFilesPendingEmit ( state : BuilderProgramState , affectedFilePendingEmit : Path , kind : BuilderFileEmit ) {
1053+ if ( ! state . affectedFilesPendingEmit ) state . affectedFilesPendingEmit = [ ] ;
1054+ if ( ! state . affectedFilesPendingEmitKind ) state . affectedFilesPendingEmitKind = createMap ( ) ;
1055+
1056+ const existingKind = state . affectedFilesPendingEmitKind . get ( affectedFilePendingEmit ) ;
1057+ state . affectedFilesPendingEmit . push ( affectedFilePendingEmit ) ;
1058+ state . affectedFilesPendingEmitKind . set ( affectedFilePendingEmit , existingKind || kind ) ;
1059+
10111060 // affectedFilesPendingEmitIndex === undefined
10121061 // - means the emit state.affectedFilesPendingEmit was undefined before adding current affected files
10131062 // so start from 0 as array would be affectedFilesPendingEmit
0 commit comments