@@ -1346,7 +1346,12 @@ namespace ts {
1346
1346
/**
1347
1347
* Reads the config file, reports errors if any and exits if the config file cannot be found
1348
1348
*/
1349
- export function getParsedCommandLineOfConfigFile ( configFileName : string , optionsToExtend : CompilerOptions , host : ParseConfigFileHost ) : ParsedCommandLine | undefined {
1349
+ export function getParsedCommandLineOfConfigFile (
1350
+ configFileName : string ,
1351
+ optionsToExtend : CompilerOptions ,
1352
+ host : ParseConfigFileHost ,
1353
+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
1354
+ ) : ParsedCommandLine | undefined {
1350
1355
let configFileText : string | undefined ;
1351
1356
try {
1352
1357
configFileText = host . readFile ( configFileName ) ;
@@ -1367,7 +1372,16 @@ namespace ts {
1367
1372
result . path = toPath ( configFileName , cwd , createGetCanonicalFileName ( host . useCaseSensitiveFileNames ) ) ;
1368
1373
result . resolvedPath = result . path ;
1369
1374
result . originalFileName = result . fileName ;
1370
- return parseJsonSourceFileConfigFileContent ( result , host , getNormalizedAbsolutePath ( getDirectoryPath ( configFileName ) , cwd ) , optionsToExtend , getNormalizedAbsolutePath ( configFileName , cwd ) ) ;
1375
+ return parseJsonSourceFileConfigFileContent (
1376
+ result ,
1377
+ host ,
1378
+ getNormalizedAbsolutePath ( getDirectoryPath ( configFileName ) , cwd ) ,
1379
+ optionsToExtend ,
1380
+ getNormalizedAbsolutePath ( configFileName , cwd ) ,
1381
+ /*resolutionStack*/ undefined ,
1382
+ /*extraFileExtension*/ undefined ,
1383
+ extendedConfigCache
1384
+ ) ;
1371
1385
}
1372
1386
1373
1387
/**
@@ -1981,8 +1995,8 @@ namespace ts {
1981
1995
* @param basePath A root directory to resolve relative path entries in the config
1982
1996
* file to. e.g. outDir
1983
1997
*/
1984
- export function parseJsonSourceFileConfigFileContent ( sourceFile : TsConfigSourceFile , host : ParseConfigHost , basePath : string , existingOptions ?: CompilerOptions , configFileName ?: string , resolutionStack ?: Path [ ] , extraFileExtensions ?: ReadonlyArray < FileExtensionInfo > ) : ParsedCommandLine {
1985
- return parseJsonConfigFileContentWorker ( /*json*/ undefined , sourceFile , host , basePath , existingOptions , configFileName , resolutionStack , extraFileExtensions ) ;
1998
+ export function parseJsonSourceFileConfigFileContent ( sourceFile : TsConfigSourceFile , host : ParseConfigHost , basePath : string , existingOptions ?: CompilerOptions , configFileName ?: string , resolutionStack ?: Path [ ] , extraFileExtensions ?: ReadonlyArray < FileExtensionInfo > , /* @internal */ extendedConfigCache ?: Map < ExtendedConfigCacheEntry > ) : ParsedCommandLine {
1999
+ return parseJsonConfigFileContentWorker ( /*json*/ undefined , sourceFile , host , basePath , existingOptions , configFileName , resolutionStack , extraFileExtensions , extendedConfigCache ) ;
1986
2000
}
1987
2001
1988
2002
/*@internal */
@@ -2021,11 +2035,12 @@ namespace ts {
2021
2035
configFileName ?: string ,
2022
2036
resolutionStack : Path [ ] = [ ] ,
2023
2037
extraFileExtensions : ReadonlyArray < FileExtensionInfo > = [ ] ,
2038
+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
2024
2039
) : ParsedCommandLine {
2025
2040
Debug . assert ( ( json === undefined && sourceFile !== undefined ) || ( json !== undefined && sourceFile === undefined ) ) ;
2026
2041
const errors : Diagnostic [ ] = [ ] ;
2027
2042
2028
- const parsedConfig = parseConfig ( json , sourceFile , host , basePath , configFileName , resolutionStack , errors ) ;
2043
+ const parsedConfig = parseConfig ( json , sourceFile , host , basePath , configFileName , resolutionStack , errors , extendedConfigCache ) ;
2029
2044
const { raw } = parsedConfig ;
2030
2045
const options = extend ( existingOptions , parsedConfig . options || { } ) ;
2031
2046
options . configFilePath = configFileName && normalizeSlashes ( configFileName ) ;
@@ -2173,7 +2188,7 @@ namespace ts {
2173
2188
return existingErrors !== configParseDiagnostics . length ;
2174
2189
}
2175
2190
2176
- interface ParsedTsconfig {
2191
+ export interface ParsedTsconfig {
2177
2192
raw : any ;
2178
2193
options ?: CompilerOptions ;
2179
2194
typeAcquisition ?: TypeAcquisition ;
@@ -2192,13 +2207,14 @@ namespace ts {
2192
2207
* It does *not* resolve the included files.
2193
2208
*/
2194
2209
function parseConfig (
2195
- json : any ,
2196
- sourceFile : TsConfigSourceFile | undefined ,
2197
- host : ParseConfigHost ,
2198
- basePath : string ,
2199
- configFileName : string | undefined ,
2200
- resolutionStack : string [ ] ,
2201
- errors : Push < Diagnostic > ,
2210
+ json : any ,
2211
+ sourceFile : TsConfigSourceFile | undefined ,
2212
+ host : ParseConfigHost ,
2213
+ basePath : string ,
2214
+ configFileName : string | undefined ,
2215
+ resolutionStack : string [ ] ,
2216
+ errors : Push < Diagnostic > ,
2217
+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
2202
2218
) : ParsedTsconfig {
2203
2219
basePath = normalizeSlashes ( basePath ) ;
2204
2220
const resolvedPath = getNormalizedAbsolutePath ( configFileName || "" , basePath ) ;
@@ -2215,7 +2231,7 @@ namespace ts {
2215
2231
if ( ownConfig . extendedConfigPath ) {
2216
2232
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
2217
2233
resolutionStack = resolutionStack . concat ( [ resolvedPath ] ) ;
2218
- const extendedConfig = getExtendedConfig ( sourceFile , ownConfig . extendedConfigPath , host , basePath , resolutionStack , errors ) ;
2234
+ const extendedConfig = getExtendedConfig ( sourceFile , ownConfig . extendedConfigPath , host , basePath , resolutionStack , errors , extendedConfigCache ) ;
2219
2235
if ( extendedConfig && isSuccessfulParsedTsconfig ( extendedConfig ) ) {
2220
2236
const baseRaw = extendedConfig . raw ;
2221
2237
const raw = ownConfig . raw ;
@@ -2359,47 +2375,65 @@ namespace ts {
2359
2375
return undefined ;
2360
2376
}
2361
2377
2378
+ export interface ExtendedConfigCacheEntry {
2379
+ extendedResult : TsConfigSourceFile ;
2380
+ extendedConfig : ParsedTsconfig | undefined ;
2381
+ }
2382
+
2362
2383
function getExtendedConfig (
2363
2384
sourceFile : TsConfigSourceFile | undefined ,
2364
2385
extendedConfigPath : string ,
2365
2386
host : ParseConfigHost ,
2366
2387
basePath : string ,
2367
2388
resolutionStack : string [ ] ,
2368
2389
errors : Push < Diagnostic > ,
2390
+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
2369
2391
) : ParsedTsconfig | undefined {
2370
- const extendedResult = readJsonConfigFile ( extendedConfigPath , path => host . readFile ( path ) ) ;
2392
+ const path = host . useCaseSensitiveFileNames ? extendedConfigPath : toLowerCase ( extendedConfigPath ) ;
2393
+ let value : ExtendedConfigCacheEntry | undefined ;
2394
+ let extendedResult : TsConfigSourceFile ;
2395
+ let extendedConfig : ParsedTsconfig | undefined ;
2396
+ if ( extendedConfigCache && ( value = extendedConfigCache . get ( path ) ) ) {
2397
+ ( { extendedResult, extendedConfig } = value ) ;
2398
+ }
2399
+ else {
2400
+ extendedResult = readJsonConfigFile ( extendedConfigPath , path => host . readFile ( path ) ) ;
2401
+ if ( ! extendedResult . parseDiagnostics . length ) {
2402
+ const extendedDirname = getDirectoryPath ( extendedConfigPath ) ;
2403
+ extendedConfig = parseConfig ( /*json*/ undefined , extendedResult , host , extendedDirname ,
2404
+ getBaseFileName ( extendedConfigPath ) , resolutionStack , errors , extendedConfigCache ) ;
2405
+
2406
+ if ( isSuccessfulParsedTsconfig ( extendedConfig ) ) {
2407
+ // Update the paths to reflect base path
2408
+ const relativeDifference = convertToRelativePath ( extendedDirname , basePath , identity ) ;
2409
+ const updatePath = ( path : string ) => isRootedDiskPath ( path ) ? path : combinePaths ( relativeDifference , path ) ;
2410
+ const mapPropertiesInRawIfNotUndefined = ( propertyName : string ) => {
2411
+ if ( raw [ propertyName ] ) {
2412
+ raw [ propertyName ] = map ( raw [ propertyName ] , updatePath ) ;
2413
+ }
2414
+ } ;
2415
+
2416
+ const { raw } = extendedConfig ;
2417
+ mapPropertiesInRawIfNotUndefined ( "include" ) ;
2418
+ mapPropertiesInRawIfNotUndefined ( "exclude" ) ;
2419
+ mapPropertiesInRawIfNotUndefined ( "files" ) ;
2420
+ }
2421
+ }
2422
+ if ( extendedConfigCache ) {
2423
+ extendedConfigCache . set ( path , { extendedResult, extendedConfig } ) ;
2424
+ }
2425
+ }
2371
2426
if ( sourceFile ) {
2372
2427
sourceFile . extendedSourceFiles = [ extendedResult . fileName ] ;
2428
+ if ( extendedResult . extendedSourceFiles ) {
2429
+ sourceFile . extendedSourceFiles . push ( ...extendedResult . extendedSourceFiles ) ;
2430
+ }
2373
2431
}
2374
2432
if ( extendedResult . parseDiagnostics . length ) {
2375
2433
errors . push ( ...extendedResult . parseDiagnostics ) ;
2376
2434
return undefined ;
2377
2435
}
2378
-
2379
- const extendedDirname = getDirectoryPath ( extendedConfigPath ) ;
2380
- const extendedConfig = parseConfig ( /*json*/ undefined , extendedResult , host , extendedDirname ,
2381
- getBaseFileName ( extendedConfigPath ) , resolutionStack , errors ) ;
2382
- if ( sourceFile && extendedResult . extendedSourceFiles ) {
2383
- sourceFile . extendedSourceFiles ! . push ( ...extendedResult . extendedSourceFiles ) ;
2384
- }
2385
-
2386
- if ( isSuccessfulParsedTsconfig ( extendedConfig ) ) {
2387
- // Update the paths to reflect base path
2388
- const relativeDifference = convertToRelativePath ( extendedDirname , basePath , identity ) ;
2389
- const updatePath = ( path : string ) => isRootedDiskPath ( path ) ? path : combinePaths ( relativeDifference , path ) ;
2390
- const mapPropertiesInRawIfNotUndefined = ( propertyName : string ) => {
2391
- if ( raw [ propertyName ] ) {
2392
- raw [ propertyName ] = map ( raw [ propertyName ] , updatePath ) ;
2393
- }
2394
- } ;
2395
-
2396
- const { raw } = extendedConfig ;
2397
- mapPropertiesInRawIfNotUndefined ( "include" ) ;
2398
- mapPropertiesInRawIfNotUndefined ( "exclude" ) ;
2399
- mapPropertiesInRawIfNotUndefined ( "files" ) ;
2400
- }
2401
-
2402
- return extendedConfig ;
2436
+ return extendedConfig ! ;
2403
2437
}
2404
2438
2405
2439
function convertCompileOnSaveOptionFromJson ( jsonOption : any , basePath : string , errors : Push < Diagnostic > ) : boolean {
0 commit comments