@@ -73,7 +73,6 @@ namespace ts {
73
73
// TODO(shkamat): update this after reworking ts build API
74
74
export function createCompilerHostWorker ( options : CompilerOptions , setParentNodes ?: boolean , system = sys ) : CompilerHost {
75
75
const existingDirectories = createMap < boolean > ( ) ;
76
-
77
76
function getCanonicalFileName ( fileName : string ) : string {
78
77
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
79
78
// otherwise use toLowerCase as a canonical form.
@@ -84,7 +83,7 @@ namespace ts {
84
83
let text : string | undefined ;
85
84
try {
86
85
performance . mark ( "beforeIORead" ) ;
87
- text = system . readFile ( fileName , options . charset ) ;
86
+ text = compilerHost . readFile ( fileName ) ;
88
87
performance . mark ( "afterIORead" ) ;
89
88
performance . measure ( "I/O Read" , "beforeIORead" , "afterIORead" ) ;
90
89
}
@@ -113,7 +112,12 @@ namespace ts {
113
112
if ( directoryPath . length > getRootLength ( directoryPath ) && ! directoryExists ( directoryPath ) ) {
114
113
const parentDirectory = getDirectoryPath ( directoryPath ) ;
115
114
ensureDirectoriesExist ( parentDirectory ) ;
116
- system . createDirectory ( directoryPath ) ;
115
+ if ( compilerHost . createDirectory ) {
116
+ compilerHost . createDirectory ( directoryPath ) ;
117
+ }
118
+ else {
119
+ system . createDirectory ( directoryPath ) ;
120
+ }
117
121
}
118
122
}
119
123
@@ -177,8 +181,7 @@ namespace ts {
177
181
178
182
const newLine = getNewLineCharacter ( options , ( ) => system . newLine ) ;
179
183
const realpath = system . realpath && ( ( path : string ) => system . realpath ! ( path ) ) ;
180
-
181
- return {
184
+ const compilerHost : CompilerHost = {
182
185
getSourceFile,
183
186
getDefaultLibLocation,
184
187
getDefaultLibFileName : options => combinePaths ( getDefaultLibLocation ( ) , getDefaultLibFileName ( options ) ) ,
@@ -194,7 +197,117 @@ namespace ts {
194
197
getEnvironmentVariable : name => system . getEnvironmentVariable ? system . getEnvironmentVariable ( name ) : "" ,
195
198
getDirectories : ( path : string ) => system . getDirectories ( path ) ,
196
199
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
198
311
} ;
199
312
}
200
313
0 commit comments