@@ -60,6 +60,7 @@ import {
60
60
isNumber ,
61
61
isString ,
62
62
map ,
63
+ mapDefinedIterator ,
63
64
maybeBind ,
64
65
noop ,
65
66
notImplemented ,
@@ -102,7 +103,7 @@ export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation
102
103
export interface ReusableDiagnosticRelatedInformation {
103
104
category : DiagnosticCategory ;
104
105
code : number ;
105
- file : string | undefined ;
106
+ file : string | undefined | false ;
106
107
start : number | undefined ;
107
108
length : number | undefined ;
108
109
messageText : string | ReusableDiagnosticMessageChain ;
@@ -384,7 +385,7 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
384
385
( state . emitDiagnosticsPerFile ??= new Map ( ) ) . set (
385
386
sourceFilePath ,
386
387
oldState ! . hasReusableDiagnostic ?
387
- convertToDiagnostics ( emitDiagnostics as readonly ReusableDiagnostic [ ] , newProgram ) :
388
+ convertToDiagnostics ( emitDiagnostics as readonly ReusableDiagnostic [ ] , sourceFilePath , newProgram ) :
388
389
repopulateDiagnostics ( emitDiagnostics as readonly Diagnostic [ ] , newProgram ) ,
389
390
) ;
390
391
}
@@ -399,7 +400,7 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
399
400
state . semanticDiagnosticsPerFile ! . set (
400
401
sourceFilePath ,
401
402
oldState ! . hasReusableDiagnostic ?
402
- convertToDiagnostics ( diagnostics as readonly ReusableDiagnostic [ ] , newProgram ) :
403
+ convertToDiagnostics ( diagnostics as readonly ReusableDiagnostic [ ] , sourceFilePath , newProgram ) :
403
404
repopulateDiagnostics ( diagnostics as readonly Diagnostic [ ] , newProgram ) ,
404
405
) ;
405
406
( state . semanticDiagnosticsFromOldState ??= new Set ( ) ) . add ( sourceFilePath ) ;
@@ -516,19 +517,19 @@ function convertOrRepopulateDiagnosticMessageChainArray<T extends DiagnosticMess
516
517
return sameMap ( array , chain => convertOrRepopulateDiagnosticMessageChain ( chain , sourceFile , newProgram , repopulateInfo ) ) ;
517
518
}
518
519
519
- function convertToDiagnostics ( diagnostics : readonly ReusableDiagnostic [ ] , newProgram : Program ) : readonly Diagnostic [ ] {
520
+ function convertToDiagnostics ( diagnostics : readonly ReusableDiagnostic [ ] , diagnosticFilePath : Path , newProgram : Program ) : readonly Diagnostic [ ] {
520
521
if ( ! diagnostics . length ) return emptyArray ;
521
522
let buildInfoDirectory : string | undefined ;
522
523
return diagnostics . map ( diagnostic => {
523
- const result : Diagnostic = convertToDiagnosticRelatedInformation ( diagnostic , newProgram , toPathInBuildInfoDirectory ) ;
524
+ const result : Diagnostic = convertToDiagnosticRelatedInformation ( diagnostic , diagnosticFilePath , newProgram , toPathInBuildInfoDirectory ) ;
524
525
result . reportsUnnecessary = diagnostic . reportsUnnecessary ;
525
526
result . reportsDeprecated = diagnostic . reportDeprecated ;
526
527
result . source = diagnostic . source ;
527
528
result . skippedOn = diagnostic . skippedOn ;
528
529
const { relatedInformation } = diagnostic ;
529
530
result . relatedInformation = relatedInformation ?
530
531
relatedInformation . length ?
531
- relatedInformation . map ( r => convertToDiagnosticRelatedInformation ( r , newProgram , toPathInBuildInfoDirectory ) ) :
532
+ relatedInformation . map ( r => convertToDiagnosticRelatedInformation ( r , diagnosticFilePath , newProgram , toPathInBuildInfoDirectory ) ) :
532
533
[ ] :
533
534
undefined ;
534
535
return result ;
@@ -540,9 +541,11 @@ function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newPro
540
541
}
541
542
}
542
543
543
- function convertToDiagnosticRelatedInformation ( diagnostic : ReusableDiagnosticRelatedInformation , newProgram : Program , toPath : ( path : string ) => Path ) : DiagnosticRelatedInformation {
544
+ function convertToDiagnosticRelatedInformation ( diagnostic : ReusableDiagnosticRelatedInformation , diagnosticFilePath : Path , newProgram : Program , toPath : ( path : string ) => Path ) : DiagnosticRelatedInformation {
544
545
const { file } = diagnostic ;
545
- const sourceFile = file ? newProgram . getSourceFileByPath ( toPath ( file ) ) : undefined ;
546
+ const sourceFile = file !== false ?
547
+ newProgram . getSourceFileByPath ( file ? toPath ( file ) : diagnosticFilePath ) :
548
+ undefined ;
546
549
return {
547
550
...diagnostic ,
548
551
file : sourceFile ,
@@ -981,7 +984,14 @@ export type ProgramBuildInfoFileId = number & { __programBuildInfoFileIdBrand: a
981
984
/** @internal */
982
985
export type ProgramBuildInfoFileIdListId = number & { __programBuildInfoFileIdListIdBrand : any ; } ;
983
986
/** @internal */
984
- export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [ fileId : ProgramBuildInfoFileId , diagnostics : readonly ReusableDiagnostic [ ] ] ;
987
+ export type ProgramBuildInfoDiagnosticOfFile = [ fileId : ProgramBuildInfoFileId , diagnostics : readonly ReusableDiagnostic [ ] ] ;
988
+ /** @internal */
989
+ export type ProgramBuildInfoDiagnostic =
990
+ | ProgramBuildInfoFileId // File is not in changedSet and still doesnt have cached diagnostics
991
+ | ProgramBuildInfoDiagnosticOfFile ; // Diagnostics for file
992
+ /** @internal */
993
+ export type ProgramBuildInfoEmitDiagnostic = ProgramBuildInfoDiagnosticOfFile ; // Diagnostics for the file
994
+
985
995
/**
986
996
* fileId if pending emit is same as what compilerOptions suggest
987
997
* [fileId] if pending emit is only dts file emit
@@ -1034,7 +1044,7 @@ export interface ProgramMultiFileEmitBuildInfo {
1034
1044
fileIdsList : readonly ( readonly ProgramBuildInfoFileId [ ] ) [ ] | undefined ;
1035
1045
referencedMap : ProgramBuildInfoReferencedMap | undefined ;
1036
1046
semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] | undefined ;
1037
- emitDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] | undefined ;
1047
+ emitDiagnosticsPerFile : ProgramBuildInfoEmitDiagnostic [ ] | undefined ;
1038
1048
affectedFilesPendingEmit : ProgramBuilderInfoFilePendingEmit [ ] | undefined ;
1039
1049
changeFileSet : readonly ProgramBuildInfoFileId [ ] | undefined ;
1040
1050
emitSignatures : readonly ProgramBuildInfoEmitSignature [ ] | undefined ;
@@ -1156,14 +1166,14 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
1156
1166
} ) ;
1157
1167
1158
1168
let referencedMap : ProgramBuildInfoReferencedMap | undefined ;
1159
- if ( state . referencedMap ) {
1169
+ if ( state . referencedMap ?. size ( ) ) {
1160
1170
referencedMap = arrayFrom ( state . referencedMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) . map ( key => [
1161
1171
toFileId ( key ) ,
1162
1172
toFileIdListId ( state . referencedMap ! . getValues ( key ) ! ) ,
1163
1173
] ) ;
1164
1174
}
1165
1175
1166
- const semanticDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics ( state . semanticDiagnosticsPerFile ) ;
1176
+ const semanticDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics ( ) ;
1167
1177
let affectedFilesPendingEmit : ProgramBuilderInfoFilePendingEmit [ ] | undefined ;
1168
1178
if ( state . affectedFilesPendingEmit ?. size ) {
1169
1179
const fullEmitForOptions = getBuilderFileEmit ( state . compilerOptions ) ;
@@ -1191,7 +1201,7 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
1191
1201
changeFileSet = append ( changeFileSet , toFileId ( path ) ) ;
1192
1202
}
1193
1203
}
1194
- const emitDiagnosticsPerFile = convertToProgramBuildInfoDiagnostics ( state . emitDiagnosticsPerFile ) ;
1204
+ const emitDiagnosticsPerFile = convertToProgramBuildInfoEmitDiagnostics ( ) ;
1195
1205
const program : ProgramMultiFileEmitBuildInfo = {
1196
1206
fileNames,
1197
1207
fileInfos,
@@ -1301,48 +1311,63 @@ function getBuildInfo(state: BuilderProgramState): BuildInfo {
1301
1311
return value ;
1302
1312
}
1303
1313
1304
- function convertToProgramBuildInfoDiagnostics ( diagnostics : Map < Path , readonly Diagnostic [ ] > | undefined ) {
1314
+ function convertToProgramBuildInfoDiagnostics ( ) {
1305
1315
let result : ProgramBuildInfoDiagnostic [ ] | undefined ;
1306
- if ( diagnostics ) {
1307
- for ( const key of arrayFrom ( diagnostics . keys ( ) ) . sort ( compareStringsCaseSensitive ) ) {
1308
- const value = diagnostics . get ( key ) ! ;
1309
- result = append (
1310
- result ,
1311
- value . length ?
1312
- [
1313
- toFileId ( key ) ,
1314
- convertToReusableDiagnostics ( value ) ,
1315
- ] :
1316
- toFileId ( key ) ,
1317
- ) ;
1316
+ state . fileInfos . forEach ( ( _value , key ) => {
1317
+ const value = state . semanticDiagnosticsPerFile ?. get ( key ) ;
1318
+ if ( ! value ) {
1319
+ if ( ! state . changedFilesSet . has ( key ) ) result = append ( result , toFileId ( key ) ) ;
1318
1320
}
1321
+ else if ( value . length ) {
1322
+ result = append ( result , [
1323
+ toFileId ( key ) ,
1324
+ convertToReusableDiagnostics ( value , key ) ,
1325
+ ] ) ;
1326
+ }
1327
+ } ) ;
1328
+ return result ;
1329
+ }
1330
+
1331
+ function convertToProgramBuildInfoEmitDiagnostics ( ) {
1332
+ let result : ProgramBuildInfoEmitDiagnostic [ ] | undefined ;
1333
+ if ( ! state . emitDiagnosticsPerFile ?. size ) return result ;
1334
+ for ( const key of arrayFrom ( state . emitDiagnosticsPerFile . keys ( ) ) . sort ( compareStringsCaseSensitive ) ) {
1335
+ const value = state . emitDiagnosticsPerFile . get ( key ) ! ;
1336
+ result = append ( result , [
1337
+ toFileId ( key ) ,
1338
+ convertToReusableDiagnostics ( value , key ) ,
1339
+ ] ) ;
1319
1340
}
1320
1341
return result ;
1321
1342
}
1322
1343
1323
- function convertToReusableDiagnostics ( diagnostics : readonly Diagnostic [ ] ) : readonly ReusableDiagnostic [ ] {
1344
+ function convertToReusableDiagnostics ( diagnostics : readonly Diagnostic [ ] , diagnosticFilePath : Path ) : readonly ReusableDiagnostic [ ] {
1324
1345
Debug . assert ( ! ! diagnostics . length ) ;
1325
1346
return diagnostics . map ( diagnostic => {
1326
- const result : ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation ( diagnostic ) ;
1347
+ const result : ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation ( diagnostic , diagnosticFilePath ) ;
1327
1348
result . reportsUnnecessary = diagnostic . reportsUnnecessary ;
1328
1349
result . reportDeprecated = diagnostic . reportsDeprecated ;
1329
1350
result . source = diagnostic . source ;
1330
1351
result . skippedOn = diagnostic . skippedOn ;
1331
1352
const { relatedInformation } = diagnostic ;
1332
1353
result . relatedInformation = relatedInformation ?
1333
1354
relatedInformation . length ?
1334
- relatedInformation . map ( r => convertToReusableDiagnosticRelatedInformation ( r ) ) :
1355
+ relatedInformation . map ( r => convertToReusableDiagnosticRelatedInformation ( r , diagnosticFilePath ) ) :
1335
1356
[ ] :
1336
1357
undefined ;
1337
1358
return result ;
1338
1359
} ) ;
1339
1360
}
1340
1361
1341
- function convertToReusableDiagnosticRelatedInformation ( diagnostic : DiagnosticRelatedInformation ) : ReusableDiagnosticRelatedInformation {
1362
+ function convertToReusableDiagnosticRelatedInformation ( diagnostic : DiagnosticRelatedInformation , diagnosticFilePath : Path ) : ReusableDiagnosticRelatedInformation {
1342
1363
const { file } = diagnostic ;
1343
1364
return {
1344
1365
...diagnostic ,
1345
- file : file ? relativeToBuildInfo ( file . resolvedPath ) : undefined ,
1366
+ file : file ?
1367
+ file . resolvedPath === diagnosticFilePath ?
1368
+ undefined :
1369
+ relativeToBuildInfo ( file . resolvedPath ) :
1370
+ false ,
1346
1371
messageText : isString ( diagnostic . messageText ) ? diagnostic . messageText : convertToReusableDiagnosticMessageChain ( diagnostic . messageText ) ,
1347
1372
} ;
1348
1373
}
@@ -1881,16 +1906,17 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo,
1881
1906
) ;
1882
1907
}
1883
1908
} ) ;
1909
+ const changedFilesSet = new Set ( map ( program . changeFileSet , toFilePath ) ) ;
1884
1910
const fullEmitForOptions = program . affectedFilesPendingEmit ? getBuilderFileEmit ( program . options || { } ) : undefined ;
1885
1911
state = {
1886
1912
fileInfos,
1887
1913
compilerOptions : program . options ? convertToOptionsWithAbsolutePaths ( program . options , toAbsolutePath ) : { } ,
1888
- referencedMap : toManyToManyPathMap ( program . referencedMap ) ,
1889
- semanticDiagnosticsPerFile : toPerFileDiagnostics ( program . semanticDiagnosticsPerFile ) ,
1890
- emitDiagnosticsPerFile : toPerFileDiagnostics ( program . emitDiagnosticsPerFile ) ,
1914
+ referencedMap : toManyToManyPathMap ( program . referencedMap , program . options ?? { } ) ,
1915
+ semanticDiagnosticsPerFile : toPerFileSemanticDiagnostics ( program . semanticDiagnosticsPerFile , fileInfos , changedFilesSet ) ,
1916
+ emitDiagnosticsPerFile : toPerFileEmitDiagnostics ( program . emitDiagnosticsPerFile ) ,
1891
1917
hasReusableDiagnostic : true ,
1892
1918
affectedFilesPendingEmit : program . affectedFilesPendingEmit && arrayToMap ( program . affectedFilesPendingEmit , value => toFilePath ( isNumber ( value ) ? value : value [ 0 ] ) , value => toBuilderFileEmit ( value , fullEmitForOptions ! ) ) ,
1893
- changedFilesSet : new Set ( map ( program . changeFileSet , toFilePath ) ) ,
1919
+ changedFilesSet,
1894
1920
latestChangedDtsFile,
1895
1921
emitSignatures : emitSignatures ?. size ? emitSignatures : undefined ,
1896
1922
} ;
@@ -1938,18 +1964,33 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo,
1938
1964
return filePathsSetList ! [ fileIdsListId - 1 ] ;
1939
1965
}
1940
1966
1941
- function toManyToManyPathMap ( referenceMap : ProgramBuildInfoReferencedMap | undefined ) : BuilderState . ManyToManyPathMap | undefined {
1942
- if ( ! referenceMap ) {
1943
- return undefined ;
1944
- }
1945
-
1946
- const map = BuilderState . createManyToManyPathMap ( ) ;
1967
+ function toManyToManyPathMap ( referenceMap : ProgramBuildInfoReferencedMap | undefined , options : CompilerOptions ) : BuilderState . ManyToManyPathMap | undefined {
1968
+ const map = BuilderState . createReferencedMap ( options ) ;
1969
+ if ( ! map || ! referenceMap ) return map ;
1947
1970
referenceMap . forEach ( ( [ fileId , fileIdListId ] ) => map . set ( toFilePath ( fileId ) , toFilePathsSet ( fileIdListId ) ) ) ;
1948
1971
return map ;
1949
1972
}
1950
1973
1951
- function toPerFileDiagnostics ( diagnostics : readonly ProgramBuildInfoDiagnostic [ ] | undefined ) : Map < Path , readonly ReusableDiagnostic [ ] > | undefined {
1952
- return diagnostics && arrayToMap ( diagnostics , value => toFilePath ( isNumber ( value ) ? value : value [ 0 ] ) , value => isNumber ( value ) ? emptyArray : value [ 1 ] ) ;
1974
+ function toPerFileSemanticDiagnostics (
1975
+ diagnostics : readonly ProgramBuildInfoDiagnostic [ ] | undefined ,
1976
+ fileInfos : Map < Path , BuilderState . FileInfo > ,
1977
+ changedFilesSet : Set < Path > ,
1978
+ ) : Map < Path , readonly ReusableDiagnostic [ ] > | undefined {
1979
+ const semanticDiagnostics = new Map < Path , readonly ReusableDiagnostic [ ] > (
1980
+ mapDefinedIterator (
1981
+ fileInfos . keys ( ) ,
1982
+ key => ! changedFilesSet . has ( key ) ? [ key , emptyArray ] : undefined ,
1983
+ ) ,
1984
+ ) ;
1985
+ diagnostics ?. forEach ( value => {
1986
+ if ( isNumber ( value ) ) semanticDiagnostics . delete ( toFilePath ( value ) ) ;
1987
+ else semanticDiagnostics . set ( toFilePath ( value [ 0 ] ) , value [ 1 ] ) ;
1988
+ } ) ;
1989
+ return semanticDiagnostics . size ? semanticDiagnostics : undefined ;
1990
+ }
1991
+
1992
+ function toPerFileEmitDiagnostics ( diagnostics : readonly ProgramBuildInfoEmitDiagnostic [ ] | undefined ) : Map < Path , readonly ReusableDiagnostic [ ] > | undefined {
1993
+ return diagnostics && arrayToMap ( diagnostics , value => toFilePath ( value [ 0 ] ) , value => value [ 1 ] ) ;
1953
1994
}
1954
1995
}
1955
1996
0 commit comments