11/*@internal */
22namespace 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+
326 export interface ReusableBuilderProgramState extends ReusableBuilderState {
427 /**
528 * Cache of semantic diagnostics for files with their Path being the key
629 */
7- semanticDiagnosticsPerFile ?: ReadonlyMap < ReadonlyArray < Diagnostic > > | undefined ;
30+ semanticDiagnosticsPerFile ?: ReadonlyMap < ReadonlyArray < ReusableDiagnostic > | ReadonlyArray < Diagnostic > > | undefined ;
831 /**
932 * The map has key by source file's path that has been changed
1033 */
@@ -46,6 +69,10 @@ namespace ts {
4669 * Current index to retrieve pending affected file
4770 */
4871 affectedFilesPendingEmitIndex ?: number | undefined ;
72+ /*
73+ * true if semantic diagnostics are ReusableDiagnostic instead of Diagnostic
74+ */
75+ hasReusableDiagnostic ?: true ;
4976 }
5077
5178 /**
@@ -200,7 +227,7 @@ namespace ts {
200227 // Unchanged file copy diagnostics
201228 const diagnostics = oldState ! . semanticDiagnosticsPerFile ! . get ( sourceFilePath ) ;
202229 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 > ) ;
204231 if ( ! state . semanticDiagnosticsFromOldState ) {
205232 state . semanticDiagnosticsFromOldState = createMap < true > ( ) ;
206233 }
@@ -225,6 +252,39 @@ namespace ts {
225252 return state ;
226253 }
227254
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+
228288 /**
229289 * Releases program and other related not needed properties
230290 */
@@ -514,12 +574,13 @@ namespace ts {
514574 return diagnostics ;
515575 }
516576
577+ export type ProgramBuildInfoDiagnostic = string | [ string , ReadonlyArray < ReusableDiagnostic > ] ;
517578 export interface ProgramBuildInfo {
518579 fileInfos : MapLike < BuilderState . FileInfo > ;
519580 options : CompilerOptions ;
520581 referencedMap ?: MapLike < string [ ] > ;
521582 exportedModulesMap ?: MapLike < string [ ] > ;
522- semanticDiagnosticsPerFile ?: string [ ] ;
583+ semanticDiagnosticsPerFile ?: ProgramBuildInfoDiagnostic [ ] ;
523584 }
524585
525586 /**
@@ -555,15 +616,57 @@ namespace ts {
555616 }
556617
557618 if ( state . semanticDiagnosticsPerFile ) {
558- const semanticDiagnosticsPerFile : string [ ] = [ ] ;
619+ const semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] = [ ] ;
559620 // 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+ ) ) ;
561631 result . semanticDiagnosticsPerFile = semanticDiagnosticsPerFile ;
562632 }
563633
564634 return result ;
565635 }
566636
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+
567670 export enum BuilderProgramKind {
568671 SemanticDiagnosticsBuilderProgram ,
569672 EmitAndSemanticDiagnosticsBuilderProgram
@@ -868,7 +971,8 @@ namespace ts {
868971 compilerOptions : program . options ,
869972 referencedMap : getMapOfReferencedSet ( program . referencedMap ) ,
870973 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
872976 } ;
873977 return {
874978 getState : ( ) => state ,
0 commit comments