@@ -53,7 +53,14 @@ export class TSService {
53
53
dirMap : new Map < string , { name : string ; path : string } > ( ) ,
54
54
} ;
55
55
56
- private readonly fileWatchCallbacks = new Map < string , ( ) => void > ( ) ;
56
+ private readonly fileWatchCallbacks = new Map <
57
+ string ,
58
+ {
59
+ setupTarget : ( ) => void ;
60
+ resetTarget : ( ) => void ;
61
+ update : ( ) => void ;
62
+ }
63
+ > ( ) ;
57
64
58
65
public constructor ( tsconfigPath : string , extraFileExtensions : string [ ] ) {
59
66
this . tsconfigPath = tsconfigPath ;
@@ -83,18 +90,28 @@ export class TSService {
83
90
if ( ! ts . sys . fileExists ( targetPath ) ) {
84
91
// Signal a directory change to request a re-scan of the directory
85
92
// because it targets a file that does not actually exist.
86
- this . fileWatchCallbacks . get ( normalizeFileName ( this . tsconfigPath ) ) ?.( ) ;
93
+ this . fileWatchCallbacks
94
+ . get ( normalizeFileName ( this . tsconfigPath ) )
95
+ ?. update ( ) ;
87
96
}
88
- getRefreshTargetFileNames ( targetPath , this . extraFileExtensions ) . forEach (
89
- ( vFilePath ) => {
90
- this . fileWatchCallbacks . get ( vFilePath ) ?.( ) ;
91
- }
92
- ) ;
93
97
}
98
+ getRefreshTargetFileNames (
99
+ lastTarget . filePath ,
100
+ this . extraFileExtensions
101
+ ) . forEach ( ( vFilePath ) => {
102
+ this . fileWatchCallbacks . get ( vFilePath ) ?. resetTarget ( ) ;
103
+ } ) ;
104
+ getRefreshTargetFileNames (
105
+ this . currTarget . filePath ,
106
+ this . extraFileExtensions
107
+ ) . forEach ( ( vFilePath ) => {
108
+ this . fileWatchCallbacks . get ( vFilePath ) ?. setupTarget ( ) ;
109
+ } ) ;
94
110
95
111
const program = this . watch . getProgram ( ) . getProgram ( ) ;
96
112
// sets parent pointers in source files
97
113
program . getTypeChecker ( ) ;
114
+
98
115
return program ;
99
116
}
100
117
@@ -168,18 +185,9 @@ export class TSService {
168
185
results . push ( file . path ) ;
169
186
}
170
187
171
- return distinctArray ( ...results ) . map ( ( result ) => {
172
- if ( ! isExtra ( result , extraFileExtensions ) ) {
173
- return result ;
174
- }
175
-
176
- if ( original . fileExists . call ( watchCompilerHost , `${ result } .d.ts` ) ) {
177
- // If the d.ts file exists, respect it and consider the virtual file not to exist.
178
- return result ;
179
- }
180
-
181
- return toVirtualTSXFileName ( result , extraFileExtensions ) ;
182
- } ) ;
188
+ return distinctArray ( ...results ) . map ( ( result ) =>
189
+ toVirtualTSXFileName ( result , extraFileExtensions )
190
+ ) ;
183
191
} ;
184
192
watchCompilerHost . readFile = ( fileName , ...args ) => {
185
193
const realFileName = toRealFileName ( fileName , extraFileExtensions ) ;
@@ -191,6 +199,23 @@ export class TSService {
191
199
current : true ,
192
200
} ) ;
193
201
}
202
+ if ( isExtraDts ( fileName , extraFileExtensions ) ) {
203
+ const real = normalizeFileName (
204
+ extraDtsToExtra ( fileName , extraFileExtensions )
205
+ ) ;
206
+ if ( this . currTarget . filePath === real ) {
207
+ // If try to read the .d.ts of the target file,
208
+ // respect the target file and consider the .d.ts doesn't exist.
209
+ return undefined ;
210
+ }
211
+ }
212
+ if ( isVirtualTSX ( fileName , extraFileExtensions ) ) {
213
+ const dts = toExtraDtsFileName ( normalized , extraFileExtensions ) ;
214
+ if ( original . fileExists . call ( watchCompilerHost , dts ) ) {
215
+ // If the .d.ts file exists, respect it and consider the virtual file not to exist.
216
+ return undefined ;
217
+ }
218
+ }
194
219
195
220
const code = original . readFile . call (
196
221
watchCompilerHost ,
@@ -251,11 +276,20 @@ export class TSService {
251
276
// It is the file currently being parsed.
252
277
return true ;
253
278
}
254
- const real = toRealFileName ( fileName , extraFileExtensions ) ;
255
- if ( original . fileExists . call ( watchCompilerHost , real , ...args ) ) {
256
- if ( real !== fileName ) {
279
+ if (
280
+ original . fileExists . call (
281
+ watchCompilerHost ,
282
+ normalizedRealFileName ,
283
+ ...args
284
+ )
285
+ ) {
286
+ if ( isVirtualTSX ( fileName , extraFileExtensions ) ) {
257
287
if (
258
- original . fileExists . call ( watchCompilerHost , `${ real } .d.ts` , ...args )
288
+ original . fileExists . call (
289
+ watchCompilerHost ,
290
+ toExtraDtsFileName ( normalizedRealFileName , extraFileExtensions ) ,
291
+ ...args
292
+ )
259
293
) {
260
294
// If the d.ts file exists, respect it and consider the virtual file not to exist.
261
295
return false ;
@@ -269,9 +303,30 @@ export class TSService {
269
303
// It keeps a callback to mark the parsed file as changed so that it can be reparsed.
270
304
watchCompilerHost . watchFile = ( fileName , callback ) => {
271
305
const normalized = normalizeFileName ( fileName ) ;
272
- this . fileWatchCallbacks . set ( normalized , ( ) =>
273
- callback ( fileName , ts . FileWatcherEventKind . Changed )
274
- ) ;
306
+ this . fileWatchCallbacks . set ( normalized , {
307
+ // The function is called when the file is targeted for parsing.
308
+ setupTarget : ( ) => {
309
+ if ( isExtraDts ( fileName , extraFileExtensions ) ) {
310
+ callback ( fileName , ts . FileWatcherEventKind . Deleted ) ;
311
+ } else if ( isVirtualTSX ( fileName , extraFileExtensions ) ) {
312
+ callback ( fileName , ts . FileWatcherEventKind . Created ) ;
313
+ } else {
314
+ callback ( fileName , ts . FileWatcherEventKind . Changed ) ;
315
+ }
316
+ } ,
317
+ // The function is called when the file leaves the target of parsing.
318
+ resetTarget : ( ) => {
319
+ if ( isExtraDts ( fileName , extraFileExtensions ) ) {
320
+ // If the .d.ts file exists, it will take respect.
321
+ callback ( fileName , ts . FileWatcherEventKind . Created ) ;
322
+ } else if ( isVirtualTSX ( fileName , extraFileExtensions ) ) {
323
+ callback ( fileName , ts . FileWatcherEventKind . Deleted ) ;
324
+ } else {
325
+ callback ( fileName , ts . FileWatcherEventKind . Changed ) ;
326
+ }
327
+ } ,
328
+ update : ( ) => callback ( fileName , ts . FileWatcherEventKind . Changed ) ,
329
+ } ) ;
275
330
276
331
return {
277
332
close : ( ) => {
@@ -322,25 +377,42 @@ function getRefreshTargetFileNames(
322
377
return [ fileName ] ;
323
378
}
324
379
325
- /** If the given filename has extra file extensions, returns the real virtual filename. */
380
+ /** If the given filename has extra extensions, returns the real virtual filename. */
326
381
function toVirtualTSXFileName ( fileName : string , extraFileExtensions : string [ ] ) {
327
382
if ( isExtra ( fileName , extraFileExtensions ) ) {
328
383
return `${ fileName } .tsx` ;
329
384
}
330
385
return fileName ;
331
386
}
332
387
388
+ /** If the given filename has extra extensions, returns the d.ts filename. */
389
+ function toExtraDtsFileName ( fileName : string , extraFileExtensions : string [ ] ) {
390
+ if ( isExtra ( fileName , extraFileExtensions ) ) {
391
+ return `${ fileName } .d.ts` ;
392
+ }
393
+ return fileName ;
394
+ }
395
+
333
396
/** If the given filename is a virtual filename (.vue.tsx), returns the real filename. */
334
397
function toRealFileName ( fileName : string , extraFileExtensions : string [ ] ) {
335
- for ( const extraFileExtension of extraFileExtensions ) {
336
- if ( fileName . endsWith ( `${ extraFileExtension } .tsx` ) ) {
337
- return fileName . slice ( 0 , - 4 ) ;
338
- }
398
+ if ( isVirtualTSX ( fileName , extraFileExtensions ) ) {
399
+ return fileName . slice ( 0 , - 4 ) ;
339
400
}
340
401
return fileName ;
341
402
}
342
403
343
- /** Checks the given filename has extra file extension or not. */
404
+ /** If the given filename is has extra extension with d.ts, returns the real filename. */
405
+ function extraDtsToExtra (
406
+ fileName : string ,
407
+ extraFileExtensions : string [ ]
408
+ ) : string {
409
+ if ( isExtraDts ( fileName , extraFileExtensions ) ) {
410
+ return fileName . slice ( 0 , - 5 ) ;
411
+ }
412
+ return fileName ;
413
+ }
414
+
415
+ /** Checks the given filename has extra extension or not. */
344
416
function isExtra ( fileName : string , extraFileExtensions : string [ ] ) : boolean {
345
417
for ( const extraFileExtension of extraFileExtensions ) {
346
418
if ( fileName . endsWith ( extraFileExtension ) ) {
@@ -350,6 +422,29 @@ function isExtra(fileName: string, extraFileExtensions: string[]): boolean {
350
422
return false ;
351
423
}
352
424
425
+ /** Checks the given filename is virtual file tsx or not. */
426
+ function isVirtualTSX (
427
+ fileName : string ,
428
+ extraFileExtensions : string [ ]
429
+ ) : boolean {
430
+ for ( const extraFileExtension of extraFileExtensions ) {
431
+ if ( fileName . endsWith ( `${ extraFileExtension } .tsx` ) ) {
432
+ return true ;
433
+ }
434
+ }
435
+ return false ;
436
+ }
437
+
438
+ /** Checks the given filename has extra extension with d.ts or not. */
439
+ function isExtraDts ( fileName : string , extraFileExtensions : string [ ] ) : boolean {
440
+ for ( const extraFileExtension of extraFileExtensions ) {
441
+ if ( fileName . endsWith ( `${ extraFileExtension } .d.ts` ) ) {
442
+ return true ;
443
+ }
444
+ }
445
+ return false ;
446
+ }
447
+
353
448
function formatDiagnostics ( diagnostics : ts . Diagnostic [ ] ) {
354
449
return ts . formatDiagnostics ( diagnostics , {
355
450
getCanonicalFileName : ( f ) => f ,
0 commit comments