@@ -73,7 +73,6 @@ namespace ts {
7373 // TODO(shkamat): update this after reworking ts build API
7474 export function createCompilerHostWorker ( options : CompilerOptions , setParentNodes ?: boolean , system = sys ) : CompilerHost {
7575 const existingDirectories = createMap < boolean > ( ) ;
76-
7776 function getCanonicalFileName ( fileName : string ) : string {
7877 // if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
7978 // otherwise use toLowerCase as a canonical form.
@@ -84,7 +83,7 @@ namespace ts {
8483 let text : string | undefined ;
8584 try {
8685 performance . mark ( "beforeIORead" ) ;
87- text = system . readFile ( fileName , options . charset ) ;
86+ text = compilerHost . readFile ( fileName ) ;
8887 performance . mark ( "afterIORead" ) ;
8988 performance . measure ( "I/O Read" , "beforeIORead" , "afterIORead" ) ;
9089 }
@@ -113,7 +112,12 @@ namespace ts {
113112 if ( directoryPath . length > getRootLength ( directoryPath ) && ! directoryExists ( directoryPath ) ) {
114113 const parentDirectory = getDirectoryPath ( directoryPath ) ;
115114 ensureDirectoriesExist ( parentDirectory ) ;
116- system . createDirectory ( directoryPath ) ;
115+ if ( compilerHost . createDirectory ) {
116+ compilerHost . createDirectory ( directoryPath ) ;
117+ }
118+ else {
119+ system . createDirectory ( directoryPath ) ;
120+ }
117121 }
118122 }
119123
@@ -177,8 +181,7 @@ namespace ts {
177181
178182 const newLine = getNewLineCharacter ( options , ( ) => system . newLine ) ;
179183 const realpath = system . realpath && ( ( path : string ) => system . realpath ! ( path ) ) ;
180-
181- return {
184+ const compilerHost : CompilerHost = {
182185 getSourceFile,
183186 getDefaultLibLocation,
184187 getDefaultLibFileName : options => combinePaths ( getDefaultLibLocation ( ) , getDefaultLibFileName ( options ) ) ,
@@ -194,7 +197,117 @@ namespace ts {
194197 getEnvironmentVariable : name => system . getEnvironmentVariable ? system . getEnvironmentVariable ( name ) : "" ,
195198 getDirectories : ( path : string ) => system . getDirectories ( path ) ,
196199 realpath,
197- readDirectory : ( path , extensions , include , exclude , depth ) => system . readDirectory ( path , extensions , include , exclude , depth )
200+ readDirectory : ( path , extensions , include , exclude , depth ) => system . readDirectory ( path , extensions , include , exclude , depth ) ,
201+ createDirectory : d => system . createDirectory ( d )
202+ } ;
203+ return compilerHost ;
204+ }
205+
206+ /*@internal */
207+ export function changeCompilerHostToUseCache (
208+ host : CompilerHost ,
209+ toPath : ( fileName : string ) => Path ,
210+ useCacheForSourceFile : boolean
211+ ) {
212+ const originalReadFile = host . readFile ;
213+ const originalFileExists = host . fileExists ;
214+ const originalDirectoryExists = host . directoryExists ;
215+ const originalCreateDirectory = host . createDirectory ;
216+ const originalWriteFile = host . writeFile ;
217+ const originalGetSourceFile = host . getSourceFile ;
218+ const readFileCache = createMap < string | false > ( ) ;
219+ const fileExistsCache = createMap < boolean > ( ) ;
220+ const directoryExistsCache = createMap < boolean > ( ) ;
221+ const sourceFileCache = createMap < SourceFile > ( ) ;
222+
223+ const readFileWithCache = ( fileName : string ) : string | undefined => {
224+ const key = toPath ( fileName ) ;
225+ const value = readFileCache . get ( key ) ;
226+ if ( value !== undefined ) return value || undefined ;
227+ return setReadFileCache ( key , fileName ) ;
228+ } ;
229+ const setReadFileCache = ( key : Path , fileName : string ) => {
230+ const newValue = originalReadFile . call ( host , fileName ) ;
231+ readFileCache . set ( key , newValue || false ) ;
232+ return newValue ;
233+ } ;
234+ host . readFile = fileName => {
235+ const key = toPath ( fileName ) ;
236+ const value = readFileCache . get ( key ) ;
237+ if ( value !== undefined ) return value ; // could be .d.ts from output
238+ if ( ! fileExtensionIs ( fileName , Extension . Json ) ) {
239+ return originalReadFile . call ( host , fileName ) ;
240+ }
241+
242+ return setReadFileCache ( key , fileName ) ;
243+ } ;
244+
245+ if ( useCacheForSourceFile ) {
246+ host . getSourceFile = ( fileName , languageVersion , onError , shouldCreateNewSourceFile ) => {
247+ const key = toPath ( fileName ) ;
248+ const value = sourceFileCache . get ( key ) ;
249+ if ( value ) return value ;
250+
251+ const sourceFile = originalGetSourceFile . call ( host , fileName , languageVersion , onError , shouldCreateNewSourceFile ) ;
252+ if ( sourceFile && ( isDeclarationFileName ( fileName ) || fileExtensionIs ( fileName , Extension . Json ) ) ) {
253+ sourceFileCache . set ( key , sourceFile ) ;
254+ }
255+ return sourceFile ;
256+ } ;
257+ }
258+
259+ // fileExists for any kind of extension
260+ host . fileExists = fileName => {
261+ const key = toPath ( fileName ) ;
262+ const value = fileExistsCache . get ( key ) ;
263+ if ( value !== undefined ) return value ;
264+ const newValue = originalFileExists . call ( host , fileName ) ;
265+ fileExistsCache . set ( key , ! ! newValue ) ;
266+ return newValue ;
267+ } ;
268+ host . writeFile = ( fileName , data , writeByteOrderMark , onError , sourceFiles ) => {
269+ const key = toPath ( fileName ) ;
270+ fileExistsCache . delete ( key ) ;
271+
272+ const value = readFileCache . get ( key ) ;
273+ if ( value && value !== data ) {
274+ readFileCache . delete ( key ) ;
275+ sourceFileCache . delete ( key ) ;
276+ }
277+ else if ( useCacheForSourceFile ) {
278+ const sourceFile = sourceFileCache . get ( key ) ;
279+ if ( sourceFile && sourceFile . text !== data ) {
280+ sourceFileCache . delete ( key ) ;
281+ }
282+ }
283+ originalWriteFile . call ( host , fileName , data , writeByteOrderMark , onError , sourceFiles ) ;
284+ } ;
285+
286+ // directoryExists
287+ if ( originalDirectoryExists && originalCreateDirectory ) {
288+ host . directoryExists = directory => {
289+ const key = toPath ( directory ) ;
290+ const value = directoryExistsCache . get ( key ) ;
291+ if ( value !== undefined ) return value ;
292+ const newValue = originalDirectoryExists . call ( host , directory ) ;
293+ directoryExistsCache . set ( key , ! ! newValue ) ;
294+ return newValue ;
295+ } ;
296+ host . createDirectory = directory => {
297+ const key = toPath ( directory ) ;
298+ directoryExistsCache . delete ( key ) ;
299+ originalCreateDirectory . call ( host , directory ) ;
300+ } ;
301+ }
302+
303+ return {
304+ originalReadFile,
305+ originalFileExists,
306+ originalDirectoryExists,
307+ originalCreateDirectory,
308+ originalWriteFile,
309+ originalGetSourceFile,
310+ readFileWithCache
198311 } ;
199312 }
200313
0 commit comments