@@ -53,7 +53,14 @@ export class TSService {
5353 dirMap : new Map < string , { name : string ; path : string } > ( ) ,
5454 } ;
5555
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+ > ( ) ;
5764
5865 public constructor ( tsconfigPath : string , extraFileExtensions : string [ ] ) {
5966 this . tsconfigPath = tsconfigPath ;
@@ -83,18 +90,28 @@ export class TSService {
8390 if ( ! ts . sys . fileExists ( targetPath ) ) {
8491 // Signal a directory change to request a re-scan of the directory
8592 // 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 ( ) ;
8796 }
88- getRefreshTargetFileNames ( targetPath , this . extraFileExtensions ) . forEach (
89- ( vFilePath ) => {
90- this . fileWatchCallbacks . get ( vFilePath ) ?.( ) ;
91- }
92- ) ;
9397 }
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+ } ) ;
94110
95111 const program = this . watch . getProgram ( ) . getProgram ( ) ;
96112 // sets parent pointers in source files
97113 program . getTypeChecker ( ) ;
114+
98115 return program ;
99116 }
100117
@@ -168,18 +185,9 @@ export class TSService {
168185 results . push ( file . path ) ;
169186 }
170187
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+ ) ;
183191 } ;
184192 watchCompilerHost . readFile = ( fileName , ...args ) => {
185193 const realFileName = toRealFileName ( fileName , extraFileExtensions ) ;
@@ -191,6 +199,23 @@ export class TSService {
191199 current : true ,
192200 } ) ;
193201 }
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+ }
194219
195220 const code = original . readFile . call (
196221 watchCompilerHost ,
@@ -251,11 +276,20 @@ export class TSService {
251276 // It is the file currently being parsed.
252277 return true ;
253278 }
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 ) ) {
257287 if (
258- original . fileExists . call ( watchCompilerHost , `${ real } .d.ts` , ...args )
288+ original . fileExists . call (
289+ watchCompilerHost ,
290+ toExtraDtsFileName ( normalizedRealFileName , extraFileExtensions ) ,
291+ ...args
292+ )
259293 ) {
260294 // If the d.ts file exists, respect it and consider the virtual file not to exist.
261295 return false ;
@@ -269,9 +303,30 @@ export class TSService {
269303 // It keeps a callback to mark the parsed file as changed so that it can be reparsed.
270304 watchCompilerHost . watchFile = ( fileName , callback ) => {
271305 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+ } ) ;
275330
276331 return {
277332 close : ( ) => {
@@ -322,25 +377,42 @@ function getRefreshTargetFileNames(
322377 return [ fileName ] ;
323378}
324379
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. */
326381function toVirtualTSXFileName ( fileName : string , extraFileExtensions : string [ ] ) {
327382 if ( isExtra ( fileName , extraFileExtensions ) ) {
328383 return `${ fileName } .tsx` ;
329384 }
330385 return fileName ;
331386}
332387
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+
333396/** If the given filename is a virtual filename (.vue.tsx), returns the real filename. */
334397function 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 ) ;
339400 }
340401 return fileName ;
341402}
342403
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. */
344416function isExtra ( fileName : string , extraFileExtensions : string [ ] ) : boolean {
345417 for ( const extraFileExtension of extraFileExtensions ) {
346418 if ( fileName . endsWith ( extraFileExtension ) ) {
@@ -350,6 +422,29 @@ function isExtra(fileName: string, extraFileExtensions: string[]): boolean {
350422 return false ;
351423}
352424
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+
353448function formatDiagnostics ( diagnostics : ts . Diagnostic [ ] ) {
354449 return ts . formatDiagnostics ( diagnostics , {
355450 getCanonicalFileName : ( f ) => f ,
0 commit comments