@@ -1341,7 +1341,12 @@ namespace ts {
13411341 /**
13421342 * Reads the config file, reports errors if any and exits if the config file cannot be found
13431343 */
1344- export function getParsedCommandLineOfConfigFile ( configFileName : string , optionsToExtend : CompilerOptions , host : ParseConfigFileHost ) : ParsedCommandLine | undefined {
1344+ export function getParsedCommandLineOfConfigFile (
1345+ configFileName : string ,
1346+ optionsToExtend : CompilerOptions ,
1347+ host : ParseConfigFileHost ,
1348+ /*@internal */ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
1349+ ) : ParsedCommandLine | undefined {
13451350 let configFileText : string | undefined ;
13461351 try {
13471352 configFileText = host . readFile ( configFileName ) ;
@@ -1362,7 +1367,16 @@ namespace ts {
13621367 result . path = toPath ( configFileName , cwd , createGetCanonicalFileName ( host . useCaseSensitiveFileNames ) ) ;
13631368 result . resolvedPath = result . path ;
13641369 result . originalFileName = result . fileName ;
1365- return parseJsonSourceFileConfigFileContent ( result , host , getNormalizedAbsolutePath ( getDirectoryPath ( configFileName ) , cwd ) , optionsToExtend , getNormalizedAbsolutePath ( configFileName , cwd ) ) ;
1370+ return parseJsonSourceFileConfigFileContent (
1371+ result ,
1372+ host ,
1373+ getNormalizedAbsolutePath ( getDirectoryPath ( configFileName ) , cwd ) ,
1374+ optionsToExtend ,
1375+ getNormalizedAbsolutePath ( configFileName , cwd ) ,
1376+ /*resolutionStack*/ undefined ,
1377+ /*extraFileExtension*/ undefined ,
1378+ extendedConfigCache
1379+ ) ;
13661380 }
13671381
13681382 /**
@@ -1976,8 +1990,8 @@ namespace ts {
19761990 * @param basePath A root directory to resolve relative path entries in the config
19771991 * file to. e.g. outDir
19781992 */
1979- export function parseJsonSourceFileConfigFileContent ( sourceFile : TsConfigSourceFile , host : ParseConfigHost , basePath : string , existingOptions ?: CompilerOptions , configFileName ?: string , resolutionStack ?: Path [ ] , extraFileExtensions ?: ReadonlyArray < FileExtensionInfo > ) : ParsedCommandLine {
1980- return parseJsonConfigFileContentWorker ( /*json*/ undefined , sourceFile , host , basePath , existingOptions , configFileName , resolutionStack , extraFileExtensions ) ;
1993+ export function parseJsonSourceFileConfigFileContent ( sourceFile : TsConfigSourceFile , host : ParseConfigHost , basePath : string , existingOptions ?: CompilerOptions , configFileName ?: string , resolutionStack ?: Path [ ] , extraFileExtensions ?: ReadonlyArray < FileExtensionInfo > , /* @internal */ extendedConfigCache ?: Map < ExtendedConfigCacheEntry > ) : ParsedCommandLine {
1994+ return parseJsonConfigFileContentWorker ( /*json*/ undefined , sourceFile , host , basePath , existingOptions , configFileName , resolutionStack , extraFileExtensions , extendedConfigCache ) ;
19811995 }
19821996
19831997 /*@internal */
@@ -2016,11 +2030,12 @@ namespace ts {
20162030 configFileName ?: string ,
20172031 resolutionStack : Path [ ] = [ ] ,
20182032 extraFileExtensions : ReadonlyArray < FileExtensionInfo > = [ ] ,
2033+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
20192034 ) : ParsedCommandLine {
20202035 Debug . assert ( ( json === undefined && sourceFile !== undefined ) || ( json !== undefined && sourceFile === undefined ) ) ;
20212036 const errors : Diagnostic [ ] = [ ] ;
20222037
2023- const parsedConfig = parseConfig ( json , sourceFile , host , basePath , configFileName , resolutionStack , errors ) ;
2038+ const parsedConfig = parseConfig ( json , sourceFile , host , basePath , configFileName , resolutionStack , errors , extendedConfigCache ) ;
20242039 const { raw } = parsedConfig ;
20252040 const options = extend ( existingOptions , parsedConfig . options || { } ) ;
20262041 options . configFilePath = configFileName && normalizeSlashes ( configFileName ) ;
@@ -2187,13 +2202,14 @@ namespace ts {
21872202 * It does *not* resolve the included files.
21882203 */
21892204 function parseConfig (
2190- json : any ,
2191- sourceFile : TsConfigSourceFile | undefined ,
2192- host : ParseConfigHost ,
2193- basePath : string ,
2194- configFileName : string | undefined ,
2195- resolutionStack : string [ ] ,
2196- errors : Push < Diagnostic > ,
2205+ json : any ,
2206+ sourceFile : TsConfigSourceFile | undefined ,
2207+ host : ParseConfigHost ,
2208+ basePath : string ,
2209+ configFileName : string | undefined ,
2210+ resolutionStack : string [ ] ,
2211+ errors : Push < Diagnostic > ,
2212+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
21972213 ) : ParsedTsconfig {
21982214 basePath = normalizeSlashes ( basePath ) ;
21992215 const resolvedPath = getNormalizedAbsolutePath ( configFileName || "" , basePath ) ;
@@ -2210,7 +2226,7 @@ namespace ts {
22102226 if ( ownConfig . extendedConfigPath ) {
22112227 // copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
22122228 resolutionStack = resolutionStack . concat ( [ resolvedPath ] ) ;
2213- const extendedConfig = getExtendedConfig ( sourceFile , ownConfig . extendedConfigPath , host , basePath , resolutionStack , errors ) ;
2229+ const extendedConfig = getExtendedConfig ( sourceFile , ownConfig . extendedConfigPath , host , basePath , resolutionStack , errors , extendedConfigCache ) ;
22142230 if ( extendedConfig && isSuccessfulParsedTsconfig ( extendedConfig ) ) {
22152231 const baseRaw = extendedConfig . raw ;
22162232 const raw = ownConfig . raw ;
@@ -2354,47 +2370,67 @@ namespace ts {
23542370 return undefined ;
23552371 }
23562372
2373+ /*@internal */
2374+ export interface ExtendedConfigCacheEntry {
2375+ extendedResult : TsConfigSourceFile ;
2376+ extendedConfig : ParsedTsconfig | undefined ;
2377+ }
2378+
23572379 function getExtendedConfig (
23582380 sourceFile : TsConfigSourceFile | undefined ,
23592381 extendedConfigPath : string ,
23602382 host : ParseConfigHost ,
23612383 basePath : string ,
23622384 resolutionStack : string [ ] ,
23632385 errors : Push < Diagnostic > ,
2386+ extendedConfigCache ?: Map < ExtendedConfigCacheEntry >
23642387 ) : ParsedTsconfig | undefined {
2365- const extendedResult = readJsonConfigFile ( extendedConfigPath , path => host . readFile ( path ) ) ;
2388+ const path = host . useCaseSensitiveFileNames ? extendedConfigPath : toLowerCase ( extendedConfigPath ) ;
2389+ let value : ExtendedConfigCacheEntry | undefined ;
2390+ let extendedResult : TsConfigSourceFile ;
2391+ let extendedConfig : ParsedTsconfig | undefined ;
2392+ if ( extendedConfigCache && ( value = extendedConfigCache . get ( path ) ) ) {
2393+ ( { extendedResult, extendedConfig } = value ) ;
2394+ }
2395+ else {
2396+ extendedResult = readJsonConfigFile ( extendedConfigPath , path => host . readFile ( path ) ) ;
2397+ if ( ! extendedResult . parseDiagnostics . length ) {
2398+ const extendedDirname = getDirectoryPath ( extendedConfigPath ) ;
2399+ extendedConfig = parseConfig ( /*json*/ undefined , extendedResult , host , extendedDirname ,
2400+ getBaseFileName ( extendedConfigPath ) , resolutionStack , errors , extendedConfigCache ) ;
2401+
2402+
2403+ if ( isSuccessfulParsedTsconfig ( extendedConfig ) ) {
2404+ // Update the paths to reflect base path
2405+ const relativeDifference = convertToRelativePath ( extendedDirname , basePath , identity ) ;
2406+ const updatePath = ( path : string ) => isRootedDiskPath ( path ) ? path : combinePaths ( relativeDifference , path ) ;
2407+ const mapPropertiesInRawIfNotUndefined = ( propertyName : string ) => {
2408+ if ( raw [ propertyName ] ) {
2409+ raw [ propertyName ] = map ( raw [ propertyName ] , updatePath ) ;
2410+ }
2411+ } ;
2412+
2413+ const { raw } = extendedConfig ;
2414+ mapPropertiesInRawIfNotUndefined ( "include" ) ;
2415+ mapPropertiesInRawIfNotUndefined ( "exclude" ) ;
2416+ mapPropertiesInRawIfNotUndefined ( "files" ) ;
2417+ }
2418+ }
2419+ if ( extendedConfigCache ) {
2420+ extendedConfigCache . set ( path , { extendedResult, extendedConfig } ) ;
2421+ }
2422+ }
23662423 if ( sourceFile ) {
23672424 sourceFile . extendedSourceFiles = [ extendedResult . fileName ] ;
2425+ if ( extendedResult . extendedSourceFiles ) {
2426+ sourceFile . extendedSourceFiles ! . push ( ...extendedResult . extendedSourceFiles ) ;
2427+ }
23682428 }
23692429 if ( extendedResult . parseDiagnostics . length ) {
23702430 errors . push ( ...extendedResult . parseDiagnostics ) ;
23712431 return undefined ;
23722432 }
2373-
2374- const extendedDirname = getDirectoryPath ( extendedConfigPath ) ;
2375- const extendedConfig = parseConfig ( /*json*/ undefined , extendedResult , host , extendedDirname ,
2376- getBaseFileName ( extendedConfigPath ) , resolutionStack , errors ) ;
2377- if ( sourceFile && extendedResult . extendedSourceFiles ) {
2378- sourceFile . extendedSourceFiles ! . push ( ...extendedResult . extendedSourceFiles ) ;
2379- }
2380-
2381- if ( isSuccessfulParsedTsconfig ( extendedConfig ) ) {
2382- // Update the paths to reflect base path
2383- const relativeDifference = convertToRelativePath ( extendedDirname , basePath , identity ) ;
2384- const updatePath = ( path : string ) => isRootedDiskPath ( path ) ? path : combinePaths ( relativeDifference , path ) ;
2385- const mapPropertiesInRawIfNotUndefined = ( propertyName : string ) => {
2386- if ( raw [ propertyName ] ) {
2387- raw [ propertyName ] = map ( raw [ propertyName ] , updatePath ) ;
2388- }
2389- } ;
2390-
2391- const { raw } = extendedConfig ;
2392- mapPropertiesInRawIfNotUndefined ( "include" ) ;
2393- mapPropertiesInRawIfNotUndefined ( "exclude" ) ;
2394- mapPropertiesInRawIfNotUndefined ( "files" ) ;
2395- }
2396-
2397- return extendedConfig ;
2433+ return extendedConfig ! ;
23982434 }
23992435
24002436 function convertCompileOnSaveOptionFromJson ( jsonOption : any , basePath : string , errors : Push < Diagnostic > ) : boolean {
0 commit comments