@@ -690,13 +690,16 @@ namespace ts {
690
690
return filterSemanticDiagnotics ( diagnostics , state . compilerOptions ) ;
691
691
}
692
692
693
- export type ProgramBuildInfoDiagnostic = string | [ string , readonly ReusableDiagnostic [ ] ] ;
694
- export type ProgramBuilderInfoFilePendingEmit = [ string , BuilderFileEmit ] ;
693
+ export type ProgramBuildInfoDiagnostic = number | [ fileId : number , diagnostics : readonly ReusableDiagnostic [ ] ] ;
694
+ export type ProgramBuilderInfoFilePendingEmit = [ fileId : number , emitKind : BuilderFileEmit ] ;
695
+ export type ProgramBuildInfoReferencedMap = [ fileId : number , fileIdListId : number ] [ ] ;
695
696
export interface ProgramBuildInfo {
696
- fileInfos : MapLike < BuilderState . FileInfo > ;
697
+ fileNames : readonly string [ ] ;
698
+ fileInfos : readonly BuilderState . FileInfo [ ] ;
697
699
options : CompilerOptions ;
698
- referencedMap ?: MapLike < string [ ] > ;
699
- exportedModulesMap ?: MapLike < string [ ] > ;
700
+ fileIdsList ?: readonly ( readonly number [ ] ) [ ] ;
701
+ referencedMap ?: ProgramBuildInfoReferencedMap ;
702
+ exportedModulesMap ?: ProgramBuildInfoReferencedMap ;
700
703
semanticDiagnosticsPerFile ?: ProgramBuildInfoDiagnostic [ ] ;
701
704
affectedFilesPendingEmit ?: ProgramBuilderInfoFilePendingEmit [ ] ;
702
705
}
@@ -708,66 +711,74 @@ namespace ts {
708
711
if ( outFile ( state . compilerOptions ) ) return undefined ;
709
712
const currentDirectory = Debug . checkDefined ( state . program ) . getCurrentDirectory ( ) ;
710
713
const buildInfoDirectory = getDirectoryPath ( getNormalizedAbsolutePath ( getTsBuildInfoEmitOutputFilePath ( state . compilerOptions ) ! , currentDirectory ) ) ;
711
- const fileInfos : MapLike < BuilderState . FileInfo > = { } ;
712
- state . fileInfos . forEach ( ( value , key ) => {
714
+ const fileNames : string [ ] = [ ] ;
715
+ const fileNameToFileId = new Map < string , number > ( ) ;
716
+ let fileIdsList : ( readonly number [ ] ) [ ] | undefined ;
717
+ let fileNamesToFileIdListId : ESMap < string , number > | undefined ;
718
+ const fileInfos = arrayFrom ( state . fileInfos . entries ( ) , ( [ key , value ] ) => {
719
+ // Ensure fileId
720
+ const fileId = toFileId ( key ) ;
721
+ Debug . assert ( fileNames [ fileId ] === relativeToBuildInfo ( key ) ) ;
713
722
const signature = state . currentAffectedFilesSignatures && state . currentAffectedFilesSignatures . get ( key ) ;
714
- fileInfos [ relativeToBuildInfo ( key ) ] = signature === undefined ? value : { version : value . version , signature, affectsGlobalScope : value . affectsGlobalScope } ;
723
+ return signature === undefined ? value : { version : value . version , signature, affectsGlobalScope : value . affectsGlobalScope } ;
715
724
} ) ;
716
725
717
- const result : ProgramBuildInfo = {
718
- fileInfos,
719
- options : convertToReusableCompilerOptions ( state . compilerOptions , relativeToBuildInfoEnsuringAbsolutePath )
720
- } ;
726
+ let referencedMap : ProgramBuildInfoReferencedMap | undefined ;
721
727
if ( state . referencedMap ) {
722
- const referencedMap : MapLike < string [ ] > = { } ;
723
- for ( const key of arrayFrom ( state . referencedMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) ) {
724
- referencedMap [ relativeToBuildInfo ( key ) ] = arrayFrom ( state . referencedMap . get ( key ) ! . keys ( ) , relativeToBuildInfo ) . sort ( compareStringsCaseSensitive ) ;
725
- }
726
- result . referencedMap = referencedMap ;
728
+ referencedMap = arrayFrom ( state . referencedMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) . map ( key => [
729
+ toFileId ( key ) ,
730
+ toFileIdListId ( state . referencedMap ! . get ( key ) ! )
731
+ ] ) ;
727
732
}
728
733
734
+ let exportedModulesMap : ProgramBuildInfoReferencedMap | undefined ;
729
735
if ( state . exportedModulesMap ) {
730
- const exportedModulesMap : MapLike < string [ ] > = { } ;
731
- for ( const key of arrayFrom ( state . exportedModulesMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) ) {
736
+ exportedModulesMap = mapDefined ( arrayFrom ( state . exportedModulesMap . keys ( ) ) . sort ( compareStringsCaseSensitive ) , key => {
732
737
const newValue = state . currentAffectedFilesExportedModulesMap && state . currentAffectedFilesExportedModulesMap . get ( key ) ;
733
738
// Not in temporary cache, use existing value
734
- if ( newValue === undefined ) exportedModulesMap [ relativeToBuildInfo ( key ) ] = arrayFrom ( state . exportedModulesMap . get ( key ) ! . keys ( ) , relativeToBuildInfo ) . sort ( compareStringsCaseSensitive ) ;
739
+ if ( newValue === undefined ) return [ toFileId ( key ) , toFileIdListId ( state . exportedModulesMap ! . get ( key ) ! ) ] ;
735
740
// Value in cache and has updated value map, use that
736
- else if ( newValue ) exportedModulesMap [ relativeToBuildInfo ( key ) ] = arrayFrom ( newValue . keys ( ) , relativeToBuildInfo ) . sort ( compareStringsCaseSensitive ) ;
737
- }
738
- result . exportedModulesMap = exportedModulesMap ;
741
+ else if ( newValue ) return [ toFileId ( key ) , toFileIdListId ( newValue ) ] ;
742
+ } ) ;
739
743
}
740
744
745
+ let semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] | undefined ;
741
746
if ( state . semanticDiagnosticsPerFile ) {
742
- const semanticDiagnosticsPerFile : ProgramBuildInfoDiagnostic [ ] = [ ] ;
743
747
for ( const key of arrayFrom ( state . semanticDiagnosticsPerFile . keys ( ) ) . sort ( compareStringsCaseSensitive ) ) {
744
748
const value = state . semanticDiagnosticsPerFile . get ( key ) ! ;
745
- semanticDiagnosticsPerFile . push (
749
+ ( semanticDiagnosticsPerFile ||= [ ] ) . push (
746
750
value . length ?
747
751
[
748
- relativeToBuildInfo ( key ) ,
752
+ toFileId ( key ) ,
749
753
state . hasReusableDiagnostic ?
750
754
value as readonly ReusableDiagnostic [ ] :
751
755
convertToReusableDiagnostics ( value as readonly Diagnostic [ ] , relativeToBuildInfo )
752
756
] :
753
- relativeToBuildInfo ( key )
757
+ toFileId ( key )
754
758
) ;
755
759
}
756
- result . semanticDiagnosticsPerFile = semanticDiagnosticsPerFile ;
757
760
}
758
761
762
+ let affectedFilesPendingEmit : ProgramBuilderInfoFilePendingEmit [ ] | undefined ;
759
763
if ( state . affectedFilesPendingEmit ) {
760
- const affectedFilesPendingEmit : ProgramBuilderInfoFilePendingEmit [ ] = [ ] ;
761
764
const seenFiles = new Set < Path > ( ) ;
762
765
for ( const path of state . affectedFilesPendingEmit . slice ( state . affectedFilesPendingEmitIndex ) . sort ( compareStringsCaseSensitive ) ) {
763
766
if ( tryAddToSet ( seenFiles , path ) ) {
764
- affectedFilesPendingEmit . push ( [ relativeToBuildInfo ( path ) , state . affectedFilesPendingEmitKind ! . get ( path ) ! ] ) ;
767
+ ( affectedFilesPendingEmit ||= [ ] ) . push ( [ toFileId ( path ) , state . affectedFilesPendingEmitKind ! . get ( path ) ! ] ) ;
765
768
}
766
769
}
767
- result . affectedFilesPendingEmit = affectedFilesPendingEmit ;
768
770
}
769
771
770
- return result ;
772
+ return {
773
+ fileNames,
774
+ fileInfos,
775
+ options : convertToReusableCompilerOptions ( state . compilerOptions , relativeToBuildInfoEnsuringAbsolutePath ) ,
776
+ fileIdsList,
777
+ referencedMap,
778
+ exportedModulesMap,
779
+ semanticDiagnosticsPerFile,
780
+ affectedFilesPendingEmit,
781
+ } ;
771
782
772
783
function relativeToBuildInfoEnsuringAbsolutePath ( path : string ) {
773
784
return relativeToBuildInfo ( getNormalizedAbsolutePath ( path , currentDirectory ) ) ;
@@ -776,6 +787,22 @@ namespace ts {
776
787
function relativeToBuildInfo ( path : string ) {
777
788
return ensurePathIsNonModuleName ( getRelativePathFromDirectory ( buildInfoDirectory , path , getCanonicalFileName ) ) ;
778
789
}
790
+
791
+ function toFileId ( path : Path ) : number {
792
+ const existing = fileNameToFileId . get ( path ) ;
793
+ if ( existing !== undefined ) return existing ;
794
+ fileNameToFileId . set ( path , fileNames . length ) ;
795
+ return fileNames . push ( relativeToBuildInfo ( path ) ) - 1 ;
796
+ }
797
+
798
+ function toFileIdListId ( set : ReadonlySet < Path > ) : number {
799
+ const fileIds = arrayFrom ( set . keys ( ) , toFileId ) . sort ( compareValues ) ;
800
+ const key = fileIds . join ( ) ;
801
+ const existing = fileNamesToFileIdListId ?. get ( key ) ;
802
+ if ( existing !== undefined ) return existing ;
803
+ ( fileNamesToFileIdListId ||= new Map ( ) ) . set ( key , fileIdsList ?. length || 0 ) ;
804
+ return ( fileIdsList ||= [ ] ) . push ( fileIds ) - 1 ;
805
+ }
779
806
}
780
807
781
808
function convertToReusableCompilerOptions ( options : CompilerOptions , relativeToBuildInfo : ( path : string ) => string ) {
@@ -1167,39 +1194,23 @@ namespace ts {
1167
1194
}
1168
1195
}
1169
1196
1170
- function getMapOfReferencedSet ( mapLike : MapLike < readonly string [ ] > | undefined , toPath : ( path : string ) => Path ) : ReadonlyESMap < Path , BuilderState . ReferencedSet > | undefined {
1171
- if ( ! mapLike ) return undefined ;
1172
- const map = new Map < Path , BuilderState . ReferencedSet > ( ) ;
1173
- // Copies keys/values from template. Note that for..in will not throw if
1174
- // template is undefined, and instead will just exit the loop.
1175
- for ( const key in mapLike ) {
1176
- if ( hasProperty ( mapLike , key ) ) {
1177
- map . set ( toPath ( key ) , new Set ( mapLike [ key ] . map ( toPath ) ) ) ;
1178
- }
1179
- }
1180
- return map ;
1181
- }
1182
-
1183
1197
export function createBuildProgramUsingProgramBuildInfo ( program : ProgramBuildInfo , buildInfoPath : string , host : ReadBuildProgramHost ) : EmitAndSemanticDiagnosticsBuilderProgram {
1184
1198
const buildInfoDirectory = getDirectoryPath ( getNormalizedAbsolutePath ( buildInfoPath , host . getCurrentDirectory ( ) ) ) ;
1185
1199
const getCanonicalFileName = createGetCanonicalFileName ( host . useCaseSensitiveFileNames ( ) ) ;
1186
1200
1201
+ const filePaths = program . fileNames . map ( toPath ) ;
1202
+ const filePathsSetList = program . fileIdsList ?. map ( fileIds => new Set ( fileIds . map ( toFilePath ) ) ) ;
1187
1203
const fileInfos = new Map < Path , BuilderState . FileInfo > ( ) ;
1188
- for ( const key in program . fileInfos ) {
1189
- if ( hasProperty ( program . fileInfos , key ) ) {
1190
- fileInfos . set ( toPath ( key ) , program . fileInfos [ key ] ) ;
1191
- }
1192
- }
1193
-
1204
+ program . fileInfos . forEach ( ( fileInfo , fileId ) => fileInfos . set ( toFilePath ( fileId ) , fileInfo ) ) ;
1194
1205
const state : ReusableBuilderProgramState = {
1195
1206
fileInfos,
1196
1207
compilerOptions : convertToOptionsWithAbsolutePaths ( program . options , toAbsolutePath ) ,
1197
- referencedMap : getMapOfReferencedSet ( program . referencedMap , toPath ) ,
1198
- exportedModulesMap : getMapOfReferencedSet ( program . exportedModulesMap , toPath ) ,
1199
- semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => toPath ( isString ( value ) ? value : value [ 0 ] ) , value => isString ( value ) ? emptyArray : value [ 1 ] ) ,
1208
+ referencedMap : toMapOfReferencedSet ( program . referencedMap ) ,
1209
+ exportedModulesMap : toMapOfReferencedSet ( program . exportedModulesMap ) ,
1210
+ semanticDiagnosticsPerFile : program . semanticDiagnosticsPerFile && arrayToMap ( program . semanticDiagnosticsPerFile , value => toFilePath ( isNumber ( value ) ? value : value [ 0 ] ) , value => isNumber ( value ) ? emptyArray : value [ 1 ] ) ,
1200
1211
hasReusableDiagnostic : true ,
1201
- affectedFilesPendingEmit : map ( program . affectedFilesPendingEmit , value => toPath ( value [ 0 ] ) ) ,
1202
- affectedFilesPendingEmitKind : program . affectedFilesPendingEmit && arrayToMap ( program . affectedFilesPendingEmit , value => toPath ( value [ 0 ] ) , value => value [ 1 ] ) ,
1212
+ affectedFilesPendingEmit : map ( program . affectedFilesPendingEmit , value => toFilePath ( value [ 0 ] ) ) ,
1213
+ affectedFilesPendingEmitKind : program . affectedFilesPendingEmit && arrayToMap ( program . affectedFilesPendingEmit , value => toFilePath ( value [ 0 ] ) , value => value [ 1 ] ) ,
1203
1214
affectedFilesPendingEmitIndex : program . affectedFilesPendingEmit && 0 ,
1204
1215
} ;
1205
1216
return {
@@ -1234,6 +1245,18 @@ namespace ts {
1234
1245
function toAbsolutePath ( path : string ) {
1235
1246
return getNormalizedAbsolutePath ( path , buildInfoDirectory ) ;
1236
1247
}
1248
+
1249
+ function toFilePath ( fileId : number ) {
1250
+ return filePaths [ fileId ] ;
1251
+ }
1252
+
1253
+ function toFilePathsSet ( fileIdsListId : number ) {
1254
+ return filePathsSetList ! [ fileIdsListId ] ;
1255
+ }
1256
+
1257
+ function toMapOfReferencedSet ( referenceMap : ProgramBuildInfoReferencedMap | undefined ) : ReadonlyESMap < Path , BuilderState . ReferencedSet > | undefined {
1258
+ return referenceMap && arrayToMap ( referenceMap , value => toFilePath ( value [ 0 ] ) , value => toFilePathsSet ( value [ 1 ] ) ) ;
1259
+ }
1237
1260
}
1238
1261
1239
1262
export function createRedirectedBuilderProgram ( state : { program : Program | undefined ; compilerOptions : CompilerOptions ; } , configFileParsingDiagnostics : readonly Diagnostic [ ] ) : BuilderProgram {
0 commit comments