1
1
import { dirname , join } from 'path' ;
2
2
import ts from 'typescript' ;
3
- import { TextDocumentContentChangeEvent } from 'vscode-languageserver' ;
3
+ import { RelativePattern , TextDocumentContentChangeEvent } from 'vscode-languageserver' ;
4
4
import { Document , DocumentManager } from '../../lib/documents' ;
5
5
import { LSConfigManager } from '../../ls-config' ;
6
6
import {
@@ -22,7 +22,7 @@ import {
22
22
import { createProjectService } from './serviceCache' ;
23
23
import { GlobalSnapshotsManager , SnapshotManager } from './SnapshotManager' ;
24
24
import { isSubPath } from './utils' ;
25
- import { FileMap } from '../../lib/documents/fileCollection' ;
25
+ import { FileMap , FileSet } from '../../lib/documents/fileCollection' ;
26
26
27
27
interface LSAndTSDocResolverOptions {
28
28
notifyExceedSizeLimit ?: ( ) => void ;
@@ -39,6 +39,8 @@ interface LSAndTSDocResolverOptions {
39
39
onProjectReloaded ?: ( ) => void ;
40
40
watch ?: boolean ;
41
41
tsSystem ?: ts . System ;
42
+ watchDirectory ?: ( patterns : RelativePattern [ ] ) => void ;
43
+ nonRecursiveWatchPattern ?: string ;
42
44
}
43
45
44
46
export class LSAndTSDocResolver {
@@ -94,7 +96,17 @@ export class LSAndTSDocResolver {
94
96
}
95
97
} ) ;
96
98
97
- this . watchers = new FileMap ( this . tsSystem . useCaseSensitiveFileNames ) ;
99
+ this . packageJsonWatchers = new FileMap ( this . tsSystem . useCaseSensitiveFileNames ) ;
100
+ this . watchedDirectories = new FileSet ( this . tsSystem . useCaseSensitiveFileNames ) ;
101
+
102
+ // workspaceUris are already watched during initialization
103
+ for ( const root of this . workspaceUris ) {
104
+ const rootPath = urlToPath ( root ) ;
105
+ if ( rootPath ) {
106
+ this . watchedDirectories . add ( rootPath ) ;
107
+ }
108
+ }
109
+
98
110
this . lsDocumentContext = {
99
111
ambientTypesSource : this . options ?. isSvelteCheck ? 'svelte-check' : 'svelte2tsx' ,
100
112
createDocument : this . createDocument ,
@@ -105,7 +117,11 @@ export class LSAndTSDocResolver {
105
117
onProjectReloaded : this . options ?. onProjectReloaded ,
106
118
watchTsConfig : ! ! this . options ?. watch ,
107
119
tsSystem : this . tsSystem ,
108
- projectService : projectService
120
+ projectService,
121
+ watchDirectory : this . options ?. watchDirectory
122
+ ? this . watchDirectory . bind ( this )
123
+ : undefined ,
124
+ nonRecursiveWatchPattern : this . options ?. nonRecursiveWatchPattern
109
125
} ;
110
126
}
111
127
@@ -131,9 +147,9 @@ export class LSAndTSDocResolver {
131
147
private getCanonicalFileName : GetCanonicalFileName ;
132
148
133
149
private userPreferencesAccessor : { preferences : ts . UserPreferences } ;
134
- private readonly watchers : FileMap < ts . FileWatcher > ;
135
-
150
+ private readonly packageJsonWatchers : FileMap < ts . FileWatcher > ;
136
151
private lsDocumentContext : LanguageServiceDocumentContext ;
152
+ private readonly watchedDirectories : FileSet ;
137
153
138
154
async getLSForPath ( path : string ) {
139
155
return ( await this . getTSService ( path ) ) . getService ( ) ;
@@ -209,15 +225,15 @@ export class LSAndTSDocResolver {
209
225
this . docManager . releaseDocument ( uri ) ;
210
226
}
211
227
212
- async invalidateModuleCache ( filePath : string ) {
213
- await forAllServices ( ( service ) => service . invalidateModuleCache ( filePath ) ) ;
228
+ async invalidateModuleCache ( filePaths : string [ ] ) {
229
+ await forAllServices ( ( service ) => service . invalidateModuleCache ( filePaths ) ) ;
214
230
}
215
231
216
232
/**
217
233
* Updates project files in all existing ts services
218
234
*/
219
- async updateProjectFiles ( ) {
220
- await forAllServices ( ( service ) => service . updateProjectFiles ( ) ) ;
235
+ async updateProjectFiles ( watcherNewFiles : string [ ] ) {
236
+ await forAllServices ( ( service ) => service . scheduleProjectFileUpdate ( watcherNewFiles ) ) ;
221
237
}
222
238
223
239
/**
@@ -227,6 +243,20 @@ export class LSAndTSDocResolver {
227
243
path : string ,
228
244
changes ?: TextDocumentContentChangeEvent [ ]
229
245
) : Promise < void > {
246
+ await this . updateExistingFile ( path , ( service ) => service . updateTsOrJsFile ( path , changes ) ) ;
247
+ }
248
+
249
+ async updateExistingSvelteFile ( path : string ) : Promise < void > {
250
+ const newDocument = this . createDocument ( path , this . tsSystem . readFile ( path ) ?? '' ) ;
251
+ await this . updateExistingFile ( path , ( service ) => {
252
+ service . updateSnapshot ( newDocument ) ;
253
+ } ) ;
254
+ }
255
+
256
+ private async updateExistingFile (
257
+ path : string ,
258
+ cb : ( service : LanguageServiceContainer ) => void
259
+ ) {
230
260
path = normalizePath ( path ) ;
231
261
// Only update once because all snapshots are shared between
232
262
// services. Since we don't have a current version of TS/JS
@@ -235,7 +265,7 @@ export class LSAndTSDocResolver {
235
265
await forAllServices ( ( service ) => {
236
266
if ( service . hasFile ( path ) && ! didUpdate ) {
237
267
didUpdate = true ;
238
- service . updateTsOrJsFile ( path , changes ) ;
268
+ cb ( service ) ;
239
269
}
240
270
} ) ;
241
271
}
@@ -290,8 +320,8 @@ export class LSAndTSDocResolver {
290
320
return {
291
321
...sys ,
292
322
readFile : ( path , encoding ) => {
293
- if ( path . endsWith ( 'package.json' ) && ! this . watchers . has ( path ) ) {
294
- this . watchers . set (
323
+ if ( path . endsWith ( 'package.json' ) && ! this . packageJsonWatchers . has ( path ) ) {
324
+ this . packageJsonWatchers . set (
295
325
path ,
296
326
watchFile ( path , this . onPackageJsonWatchChange . bind ( this ) , 3_000 )
297
327
) ;
@@ -309,8 +339,8 @@ export class LSAndTSDocResolver {
309
339
const normalizedPath = projectService ?. toPath ( path ) ;
310
340
311
341
if ( onWatchChange === ts . FileWatcherEventKind . Deleted ) {
312
- this . watchers . get ( path ) ?. close ( ) ;
313
- this . watchers . delete ( path ) ;
342
+ this . packageJsonWatchers . get ( path ) ?. close ( ) ;
343
+ this . packageJsonWatchers . delete ( path ) ;
314
344
packageJsonCache ?. delete ( normalizedPath ) ;
315
345
} else {
316
346
packageJsonCache ?. addOrUpdate ( normalizedPath ) ;
@@ -345,4 +375,20 @@ export class LSAndTSDocResolver {
345
375
this . globalSnapshotsManager . updateTsOrJsFile ( snapshot . filePath ) ;
346
376
} ) ;
347
377
}
378
+
379
+ private watchDirectory ( patterns : RelativePattern [ ] ) {
380
+ if ( ! this . options ?. watchDirectory || patterns . length === 0 ) {
381
+ return ;
382
+ }
383
+
384
+ for ( const pattern of patterns ) {
385
+ const uri = typeof pattern . baseUri === 'string' ? pattern . baseUri : pattern . baseUri . uri ;
386
+ for ( const watched of this . watchedDirectories ) {
387
+ if ( isSubPath ( watched , uri , this . getCanonicalFileName ) ) {
388
+ return ;
389
+ }
390
+ }
391
+ }
392
+ this . options . watchDirectory ( patterns ) ;
393
+ }
348
394
}
0 commit comments