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,39 @@ 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
+ return result ;
267
+ } ) ;
268
+ }
269
+
270
+ function convertToDiagnosticRelatedInformation ( diagnostic : ReusableDiagnosticRelatedInformation , newProgram : Program ) : DiagnosticRelatedInformation {
271
+ const { file, messageText } = diagnostic ;
272
+ return {
273
+ ...diagnostic ,
274
+ file : file && newProgram . getSourceFileByPath ( file ) ,
275
+ messageText : messageText === undefined || isString ( messageText ) ?
276
+ messageText :
277
+ convertToDiagnosticMessageChain ( messageText , newProgram )
278
+ } ;
279
+ }
280
+
281
+ function convertToDiagnosticMessageChain ( diagnostic : ReusableDiagnosticMessageChain , newProgram : Program ) : DiagnosticMessageChain {
282
+ return {
283
+ ...diagnostic ,
284
+ next : diagnostic . next && convertToDiagnosticMessageChain ( diagnostic . next , newProgram )
285
+ } ;
286
+ }
287
+
228
288
/**
229
289
* Releases program and other related not needed properties
230
290
*/
@@ -514,12 +574,13 @@ namespace ts {
514
574
return diagnostics ;
515
575
}
516
576
577
+ export type ProgramBuildInfoDiagnostic = string | [ string , ReadonlyArray < ReusableDiagnostic > ] ;
517
578
export interface ProgramBuildInfo {
518
579
fileInfos : MapLike < BuilderState . FileInfo > ;
519
580
options : CompilerOptions ;
520
581
referencedMap ?: MapLike < string [ ] > ;
521
582
exportedModulesMap ?: MapLike < string [ ] > ;
522
- semanticDiagnosticsPerFile ?: string [ ] ;
583
+ semanticDiagnosticsPerFile ?: ProgramBuildInfoDiagnostic [ ] ;
523
584
}
524
585
525
586
/**
@@ -555,15 +616,57 @@ namespace ts {
555
616
}
556
617
557
618
if ( state . semanticDiagnosticsPerFile ) {
558
- const semanticDiagnosticsPerFile : string [ ] = [ ] ;
619
+ const semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] = [ ] ;
559
620
// Currently not recording actual errors since those mean no emit for tsc --build
560
- state . semanticDiagnosticsPerFile . forEach ( ( _value , key ) => semanticDiagnosticsPerFile . push ( key ) ) ;
621
+ state . semanticDiagnosticsPerFile . forEach ( ( value , key ) => semanticDiagnosticsPerFile . push (
622
+ value . length ?
623
+ [
624
+ key ,
625
+ state . hasReusableDiagnostic ?
626
+ value as ReadonlyArray < ReusableDiagnostic > :
627
+ convertToReusableDiagnostics ( value as ReadonlyArray < Diagnostic > )
628
+ ] :
629
+ key
630
+ ) ) ;
561
631
result . semanticDiagnosticsPerFile = semanticDiagnosticsPerFile ;
562
632
}
563
633
564
634
return result ;
565
635
}
566
636
637
+ function convertToReusableDiagnostics ( diagnostics : ReadonlyArray < Diagnostic > ) : ReadonlyArray < ReusableDiagnostic > {
638
+ Debug . assert ( ! ! diagnostics . length ) ;
639
+ return diagnostics . map ( diagnostic => {
640
+ const result : ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation ( diagnostic ) ;
641
+ result . reportsUnnecessary = diagnostic . reportsUnnecessary ;
642
+ result . source = diagnostic . source ;
643
+ const { relatedInformation } = diagnostic ;
644
+ result . relatedInformation = relatedInformation &&
645
+ relatedInformation . length ?
646
+ relatedInformation . map ( r => convertToReusableDiagnosticRelatedInformation ( r ) ) :
647
+ emptyArray ;
648
+ return result ;
649
+ } ) ;
650
+ }
651
+
652
+ function convertToReusableDiagnosticRelatedInformation ( diagnostic : DiagnosticRelatedInformation ) : ReusableDiagnosticRelatedInformation {
653
+ const { file, messageText } = diagnostic ;
654
+ return {
655
+ ...diagnostic ,
656
+ file : file && file . path ,
657
+ messageText : messageText === undefined || isString ( messageText ) ?
658
+ messageText :
659
+ convertToReusableDiagnosticMessageChain ( messageText )
660
+ } ;
661
+ }
662
+
663
+ function convertToReusableDiagnosticMessageChain ( diagnostic : DiagnosticMessageChain ) : ReusableDiagnosticMessageChain {
664
+ return {
665
+ ...diagnostic ,
666
+ next : diagnostic . next && convertToReusableDiagnosticMessageChain ( diagnostic . next )
667
+ } ;
668
+ }
669
+
567
670
export enum BuilderProgramKind {
568
671
SemanticDiagnosticsBuilderProgram ,
569
672
EmitAndSemanticDiagnosticsBuilderProgram
@@ -868,7 +971,8 @@ namespace ts {
868
971
compilerOptions : program . options ,
869
972
referencedMap : getMapOfReferencedSet ( program . referencedMap ) ,
870
973
exportedModulesMap : getMapOfReferencedSet ( program . exportedModulesMap ) ,
871
- semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , identity , ( ) => emptyArray )
974
+ semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => isString ( value ) ? value : value [ 0 ] , value => isString ( value ) ? emptyArray : value [ 1 ] ) ,
975
+ hasReusableDiagnostic : true
872
976
} ;
873
977
return {
874
978
getState : ( ) => state ,
0 commit comments