@@ -54,6 +54,18 @@ namespace ts {
54
54
* compilerOptions for the program
55
55
*/
56
56
compilerOptions : CompilerOptions ;
57
+ /**
58
+ * Files pending to be emitted
59
+ */
60
+ affectedFilesPendingEmit : ReadonlyArray < Path > | undefined ;
61
+ /**
62
+ * Current index to retrieve pending affected file
63
+ */
64
+ affectedFilesPendingEmitIndex : number | undefined ;
65
+ /**
66
+ * Already seen affected files
67
+ */
68
+ seenEmittedFiles : Map < true > | undefined ;
57
69
}
58
70
59
71
function hasSameKeys < T , U > ( map1 : ReadonlyMap < T > | undefined , map2 : ReadonlyMap < U > | undefined ) : boolean {
@@ -89,6 +101,10 @@ namespace ts {
89
101
90
102
// Copy old state's changed files set
91
103
copyEntries ( oldState ! . changedFilesSet , state . changedFilesSet ) ;
104
+ if ( ! compilerOptions . outFile && ! compilerOptions . out && oldState ! . affectedFilesPendingEmit ) {
105
+ state . affectedFilesPendingEmit = oldState ! . affectedFilesPendingEmit ;
106
+ state . affectedFilesPendingEmitIndex = oldState ! . affectedFilesPendingEmitIndex ;
107
+ }
92
108
}
93
109
94
110
// Update changed files and copy semantic diagnostics if we can
@@ -203,6 +219,27 @@ namespace ts {
203
219
}
204
220
}
205
221
222
+ /**
223
+ * Returns next file to be emitted from files that retrieved semantic diagnostics but did not emit yet
224
+ */
225
+ function getNextAffectedFilePendingEmit ( state : BuilderProgramState ) : SourceFile | undefined {
226
+ const { affectedFilesPendingEmit } = state ;
227
+ if ( affectedFilesPendingEmit ) {
228
+ const seenEmittedFiles = state . seenEmittedFiles || ( state . seenEmittedFiles = createMap ( ) ) ;
229
+ for ( let affectedFilesIndex = state . affectedFilesPendingEmitIndex ! ; affectedFilesIndex < affectedFilesPendingEmit . length ; affectedFilesIndex ++ ) {
230
+ const affectedFile = Debug . assertDefined ( state . program ) . getSourceFileByPath ( affectedFilesPendingEmit [ affectedFilesIndex ] ) ;
231
+ if ( affectedFile && ! seenEmittedFiles . has ( affectedFile . path ) ) {
232
+ // emit this file
233
+ state . affectedFilesPendingEmitIndex = affectedFilesIndex ;
234
+ return affectedFile ;
235
+ }
236
+ }
237
+ state . affectedFilesPendingEmit = undefined ;
238
+ state . affectedFilesPendingEmitIndex = undefined ;
239
+ }
240
+ return undefined ;
241
+ }
242
+
206
243
/**
207
244
* Remove the semantic diagnostics cached from old state for affected File and the files that are referencing modules that export entities from affected file
208
245
*/
@@ -312,21 +349,26 @@ namespace ts {
312
349
* This is called after completing operation on the next affected file.
313
350
* The operations here are postponed to ensure that cancellation during the iteration is handled correctly
314
351
*/
315
- function doneWithAffectedFile ( state : BuilderProgramState , affected : SourceFile | Program ) {
352
+ function doneWithAffectedFile ( state : BuilderProgramState , affected : SourceFile | Program , isPendingEmit ?: boolean ) {
316
353
if ( affected === state . program ) {
317
354
state . changedFilesSet . clear ( ) ;
318
355
}
319
356
else {
320
357
state . seenAffectedFiles ! . set ( ( affected as SourceFile ) . path , true ) ;
321
- state . affectedFilesIndex ! ++ ;
358
+ if ( isPendingEmit ) {
359
+ state . affectedFilesPendingEmitIndex ! ++ ;
360
+ }
361
+ else {
362
+ state . affectedFilesIndex ! ++ ;
363
+ }
322
364
}
323
365
}
324
366
325
367
/**
326
368
* Returns the result with affected file
327
369
*/
328
- function toAffectedFileResult < T > ( state : BuilderProgramState , result : T , affected : SourceFile | Program ) : AffectedFileResult < T > {
329
- doneWithAffectedFile ( state , affected ) ;
370
+ function toAffectedFileResult < T > ( state : BuilderProgramState , result : T , affected : SourceFile | Program , isPendingEmit ?: boolean ) : AffectedFileResult < T > {
371
+ doneWithAffectedFile ( state , affected , isPendingEmit ) ;
330
372
return { result, affected } ;
331
373
}
332
374
@@ -442,18 +484,29 @@ namespace ts {
442
484
* in that order would be used to write the files
443
485
*/
444
486
function emitNextAffectedFile ( writeFile ?: WriteFileCallback , cancellationToken ?: CancellationToken , emitOnlyDtsFiles ?: boolean , customTransformers ?: CustomTransformers ) : AffectedFileResult < EmitResult > {
445
- const affected = getNextAffectedFile ( state , cancellationToken , computeHash ) ;
487
+ let affected = getNextAffectedFile ( state , cancellationToken , computeHash ) ;
488
+ let isPendingEmitFile = false ;
446
489
if ( ! affected ) {
490
+ affected = getNextAffectedFilePendingEmit ( state ) ;
447
491
// Done
448
- return undefined ;
492
+ if ( ! affected ) {
493
+ return undefined ;
494
+ }
495
+ isPendingEmitFile = true ;
496
+ }
497
+
498
+ // Mark seen emitted files if there are pending files to be emitted
499
+ if ( state . affectedFilesPendingEmit && state . program !== affected ) {
500
+ ( state . seenEmittedFiles || ( state . seenEmittedFiles = createMap ( ) ) ) . set ( ( affected as SourceFile ) . path , true ) ;
449
501
}
450
502
451
503
return toAffectedFileResult (
452
504
state ,
453
505
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
454
506
// Otherwise just affected file
455
507
Debug . assertDefined ( state . program ) . emit ( affected === state . program ? undefined : affected as SourceFile , writeFile || host . writeFile , cancellationToken , emitOnlyDtsFiles , customTransformers ) ,
456
- affected
508
+ affected ,
509
+ isPendingEmitFile
457
510
) ;
458
511
}
459
512
@@ -552,12 +605,22 @@ namespace ts {
552
605
return getSemanticDiagnosticsOfFile ( state , sourceFile , cancellationToken ) ;
553
606
}
554
607
555
- if ( kind === BuilderProgramKind . SemanticDiagnosticsBuilderProgram ) {
556
- // When semantic builder asks for diagnostics of the whole program,
557
- // ensure that all the affected files are handled
558
- let affected : SourceFile | Program | undefined ;
559
- while ( affected = getNextAffectedFile ( state , cancellationToken , computeHash ) ) {
560
- doneWithAffectedFile ( state , affected ) ;
608
+ // When semantic builder asks for diagnostics of the whole program,
609
+ // ensure that all the affected files are handled
610
+ let affected : SourceFile | Program | undefined ;
611
+ let affectedFilesPendingEmit : Path [ ] | undefined ;
612
+ while ( affected = getNextAffectedFile ( state , cancellationToken , computeHash ) ) {
613
+ if ( affected !== state . program && kind === BuilderProgramKind . EmitAndSemanticDiagnosticsBuilderProgram ) {
614
+ ( affectedFilesPendingEmit || ( affectedFilesPendingEmit = [ ] ) ) . push ( ( affected as SourceFile ) . path ) ;
615
+ }
616
+ doneWithAffectedFile ( state , affected ) ;
617
+ }
618
+
619
+ // In case of emit builder, cache the files to be emitted
620
+ if ( affectedFilesPendingEmit ) {
621
+ state . affectedFilesPendingEmit = concatenate ( state . affectedFilesPendingEmit , affectedFilesPendingEmit ) ;
622
+ if ( state . affectedFilesPendingEmitIndex === undefined ) {
623
+ state . affectedFilesPendingEmitIndex = 0 ;
561
624
}
562
625
}
563
626
0 commit comments