1
1
/*@internal */
2
2
namespace ts {
3
+ export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation {
4
+ /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */
5
+ reportsUnnecessary ?: { } ;
6
+ source ?: string ;
7
+ relatedInformation ?: ReusableDiagnosticRelatedInformation [ ] ;
8
+ }
9
+
10
+ export interface ReusableDiagnosticRelatedInformation {
11
+ category : DiagnosticCategory ;
12
+ code : number ;
13
+ file : Path | undefined ;
14
+ start : number | undefined ;
15
+ length : number | undefined ;
16
+ messageText : string | ReusableDiagnosticMessageChain ;
17
+ }
18
+
19
+ export interface ReusableDiagnosticMessageChain {
20
+ messageText : string ;
21
+ category : DiagnosticCategory ;
22
+ code : number ;
23
+ next ?: ReusableDiagnosticMessageChain ;
24
+ }
25
+
3
26
export interface ReusableBuilderProgramState extends ReusableBuilderState {
4
27
/**
5
28
* Cache of semantic diagnostics for files with their Path being the key
6
29
*/
7
- semanticDiagnosticsPerFile ?: ReadonlyMap < ReadonlyArray < Diagnostic > > | undefined ;
30
+ semanticDiagnosticsPerFile ?: ReadonlyMap < ReadonlyArray < ReusableDiagnostic > | ReadonlyArray < Diagnostic > > | undefined ;
8
31
/**
9
32
* The map has key by source file's path that has been changed
10
33
*/
@@ -46,6 +69,10 @@ namespace ts {
46
69
* Current index to retrieve pending affected file
47
70
*/
48
71
affectedFilesPendingEmitIndex ?: number | undefined ;
72
+ /*
73
+ * true if semantic diagnostics are ReusableDiagnostic instead of Diagnostic
74
+ */
75
+ hasReusableDiagnostic ?: true ;
49
76
}
50
77
51
78
/**
@@ -200,7 +227,7 @@ namespace ts {
200
227
// Unchanged file copy diagnostics
201
228
const diagnostics = oldState ! . semanticDiagnosticsPerFile ! . get ( sourceFilePath ) ;
202
229
if ( diagnostics ) {
203
- state . semanticDiagnosticsPerFile ! . set ( sourceFilePath , diagnostics ) ;
230
+ state . semanticDiagnosticsPerFile ! . set ( sourceFilePath , oldState ! . hasReusableDiagnostic ? convertToDiagnostics ( diagnostics as ReadonlyArray < ReusableDiagnostic > , newProgram ) : diagnostics as ReadonlyArray < Diagnostic > ) ;
204
231
if ( ! state . semanticDiagnosticsFromOldState ) {
205
232
state . semanticDiagnosticsFromOldState = createMap < true > ( ) ;
206
233
}
@@ -225,6 +252,40 @@ namespace ts {
225
252
return state ;
226
253
}
227
254
255
+ function convertToDiagnostics ( diagnostics : ReadonlyArray < ReusableDiagnostic > , newProgram : Program ) : ReadonlyArray < Diagnostic > {
256
+ if ( ! diagnostics . length ) return emptyArray ;
257
+ return diagnostics . map ( diagnostic => {
258
+ const result : Diagnostic = convertToDiagnosticRelatedInformation ( diagnostic , newProgram ) ;
259
+ result . reportsUnnecessary = diagnostic . reportsUnnecessary ;
260
+ result . source = diagnostic . source ;
261
+ const { relatedInformation } = diagnostic ;
262
+ result . relatedInformation = relatedInformation ?
263
+ relatedInformation . length ?
264
+ relatedInformation . map ( r => convertToDiagnosticRelatedInformation ( r , newProgram ) ) :
265
+ emptyArray :
266
+ undefined ;
267
+ return result ;
268
+ } ) ;
269
+ }
270
+
271
+ function convertToDiagnosticRelatedInformation ( diagnostic : ReusableDiagnosticRelatedInformation , newProgram : Program ) : DiagnosticRelatedInformation {
272
+ const { file, messageText } = diagnostic ;
273
+ return {
274
+ ...diagnostic ,
275
+ file : file && newProgram . getSourceFileByPath ( file ) ,
276
+ messageText : messageText === undefined || isString ( messageText ) ?
277
+ messageText :
278
+ convertToDiagnosticMessageChain ( messageText , newProgram )
279
+ } ;
280
+ }
281
+
282
+ function convertToDiagnosticMessageChain ( diagnostic : ReusableDiagnosticMessageChain , newProgram : Program ) : DiagnosticMessageChain {
283
+ return {
284
+ ...diagnostic ,
285
+ next : diagnostic . next && convertToDiagnosticMessageChain ( diagnostic . next , newProgram )
286
+ } ;
287
+ }
288
+
228
289
/**
229
290
* Releases program and other related not needed properties
230
291
*/
@@ -514,12 +575,13 @@ namespace ts {
514
575
return diagnostics ;
515
576
}
516
577
578
+ export type ProgramBuildInfoDiagnostic = string | [ string , ReadonlyArray < ReusableDiagnostic > ] ;
517
579
export interface ProgramBuildInfo {
518
580
fileInfos : MapLike < BuilderState . FileInfo > ;
519
581
options : CompilerOptions ;
520
582
referencedMap ?: MapLike < string [ ] > ;
521
583
exportedModulesMap ?: MapLike < string [ ] > ;
522
- semanticDiagnosticsPerFile ?: string [ ] ;
584
+ semanticDiagnosticsPerFile ?: ProgramBuildInfoDiagnostic [ ] ;
523
585
}
524
586
525
587
/**
@@ -555,15 +617,58 @@ namespace ts {
555
617
}
556
618
557
619
if ( state . semanticDiagnosticsPerFile ) {
558
- const semanticDiagnosticsPerFile : string [ ] = [ ] ;
620
+ const semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] = [ ] ;
559
621
// Currently not recording actual errors since those mean no emit for tsc --build
560
- state . semanticDiagnosticsPerFile . forEach ( ( _value , key ) => semanticDiagnosticsPerFile . push ( key ) ) ;
622
+ state . semanticDiagnosticsPerFile . forEach ( ( value , key ) => semanticDiagnosticsPerFile . push (
623
+ value . length ?
624
+ [
625
+ key ,
626
+ state . hasReusableDiagnostic ?
627
+ value as ReadonlyArray < ReusableDiagnostic > :
628
+ convertToReusableDiagnostics ( value as ReadonlyArray < Diagnostic > )
629
+ ] :
630
+ key
631
+ ) ) ;
561
632
result . semanticDiagnosticsPerFile = semanticDiagnosticsPerFile ;
562
633
}
563
634
564
635
return result ;
565
636
}
566
637
638
+ function convertToReusableDiagnostics ( diagnostics : ReadonlyArray < Diagnostic > ) : ReadonlyArray < ReusableDiagnostic > {
639
+ Debug . assert ( ! ! diagnostics . length ) ;
640
+ return diagnostics . map ( diagnostic => {
641
+ const result : ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation ( diagnostic ) ;
642
+ result . reportsUnnecessary = diagnostic . reportsUnnecessary ;
643
+ result . source = diagnostic . source ;
644
+ const { relatedInformation } = diagnostic ;
645
+ result . relatedInformation = relatedInformation ?
646
+ relatedInformation . length ?
647
+ relatedInformation . map ( r => convertToReusableDiagnosticRelatedInformation ( r ) ) :
648
+ emptyArray :
649
+ undefined ;
650
+ return result ;
651
+ } ) ;
652
+ }
653
+
654
+ function convertToReusableDiagnosticRelatedInformation ( diagnostic : DiagnosticRelatedInformation ) : ReusableDiagnosticRelatedInformation {
655
+ const { file, messageText } = diagnostic ;
656
+ return {
657
+ ...diagnostic ,
658
+ file : file && file . path ,
659
+ messageText : messageText === undefined || isString ( messageText ) ?
660
+ messageText :
661
+ convertToReusableDiagnosticMessageChain ( messageText )
662
+ } ;
663
+ }
664
+
665
+ function convertToReusableDiagnosticMessageChain ( diagnostic : DiagnosticMessageChain ) : ReusableDiagnosticMessageChain {
666
+ return {
667
+ ...diagnostic ,
668
+ next : diagnostic . next && convertToReusableDiagnosticMessageChain ( diagnostic . next )
669
+ } ;
670
+ }
671
+
567
672
export enum BuilderProgramKind {
568
673
SemanticDiagnosticsBuilderProgram ,
569
674
EmitAndSemanticDiagnosticsBuilderProgram
@@ -868,7 +973,8 @@ namespace ts {
868
973
compilerOptions : program . options ,
869
974
referencedMap : getMapOfReferencedSet ( program . referencedMap ) ,
870
975
exportedModulesMap : getMapOfReferencedSet ( program . exportedModulesMap ) ,
871
- semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , identity , ( ) => emptyArray )
976
+ semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => isString ( value ) ? value : value [ 0 ] , value => isString ( value ) ? emptyArray : value [ 1 ] ) ,
977
+ hasReusableDiagnostic : true
872
978
} ;
873
979
return {
874
980
getState : ( ) => state ,
0 commit comments