4
4
} from "../../../../harness/tsserverLogger" ;
5
5
import {
6
6
createWatchUtils ,
7
+ Watches ,
7
8
WatchUtils ,
8
9
} from "../../../../harness/watchUtils" ;
9
10
import * as ts from "../../../_namespaces/ts" ;
@@ -60,11 +61,11 @@ describe("unittests:: tsserver:: events:: watchEvents", () => {
60
61
}
61
62
62
63
function watchDirectory ( data : ts . server . protocol . CreateDirectoryWatcherEventBody ) {
63
- logger . log ( `Custom watchDirectory: ${ data . id } : ${ data . path } ${ data . recursive } ` ) ;
64
+ logger . log ( `Custom watchDirectory: ${ data . id } : ${ data . path } ${ data . recursive } ${ data . ignoreUpdate } ` ) ;
64
65
ts . Debug . assert ( ! idToClose . has ( data . id ) ) ;
65
66
const result = host . factoryData . watchUtils . fsWatch ( data . path , data . recursive , data ) ;
66
67
idToClose . set ( data . id , ( ) => {
67
- logger . log ( `Custom watchDirectory:: Close:: ${ data . id } : ${ data . path } ${ data . recursive } ` ) ;
68
+ logger . log ( `Custom watchDirectory:: Close:: ${ data . id } : ${ data . path } ${ data . recursive } ${ data . ignoreUpdate } ` ) ;
68
69
result . close ( ) ;
69
70
} ) ;
70
71
}
@@ -89,37 +90,132 @@ describe("unittests:: tsserver:: events:: watchEvents", () => {
89
90
}
90
91
}
91
92
92
- function updateFileOnHost ( session : TestSession , file : string , log : string ) {
93
+ function updateFileOnHost ( session : TestSession , file : string , log : string , content ?: string ) {
93
94
// Change b.ts
94
- session . logger . log ( log ) ;
95
- session . host . writeFile ( file , session . host . readFile ( "/user/username/projects/myproject/a.ts" ) ! ) ;
95
+ session . logger . log ( `${ log } : ${ file } ` ) ;
96
+ if ( content ) session . host . appendFile ( file , content ) ;
97
+ else session . host . writeFile ( file , session . host . readFile ( "/user/username/projects/myproject/a.ts" ) ! ) ;
96
98
session . host . runQueuedTimeoutCallbacks ( ) ;
97
99
}
98
100
101
+ function collectWatchChanges < T extends ts . server . protocol . CreateFileWatcherEventBody | ts . server . protocol . CreateDirectoryWatcherEventBody > (
102
+ session : TestSession ,
103
+ watches : Watches < T > ,
104
+ path : string ,
105
+ eventPath : string ,
106
+ eventType : "created" | "deleted" | "updated" ,
107
+ ignoreUpdate ?: ( data : T ) => boolean ,
108
+ ) {
109
+ session . logger . log ( `Custom watch:: ${ path } ${ eventPath } ${ eventType } ` ) ;
110
+ let result : ts . server . protocol . WatchChangeRequestArgs [ ] | undefined ;
111
+ watches . forEach (
112
+ path ,
113
+ data => {
114
+ if ( ignoreUpdate ?.( data ) ) return ;
115
+ switch ( eventType ) {
116
+ case "created" :
117
+ ( result ??= [ ] ) . push ( { id : data . id , created : [ eventPath ] } ) ;
118
+ break ;
119
+ case "deleted" :
120
+ ( result ??= [ ] ) . push ( { id : data . id , deleted : [ eventPath ] } ) ;
121
+ break ;
122
+ case "updated" :
123
+ ( result ??= [ ] ) . push ( { id : data . id , updated : [ eventPath ] } ) ;
124
+ break ;
125
+ default :
126
+ ts . Debug . assertNever ( eventType ) ;
127
+ }
128
+ } ,
129
+ ) ;
130
+ return result ;
131
+ }
132
+
133
+ function collectDirectoryWatcherChanges (
134
+ session : TestSession ,
135
+ dir : string ,
136
+ eventPath : string ,
137
+ eventType : "created" | "deleted" | "updated" ,
138
+ ) {
139
+ return collectWatchChanges (
140
+ session ,
141
+ ( session . logger . host as TestServerHostWithCustomWatch ) . factoryData . watchUtils . fsWatchesRecursive ,
142
+ dir ,
143
+ eventPath ,
144
+ eventType ,
145
+ data => ! ! data . ignoreUpdate && eventType === "updated" ,
146
+ ) ;
147
+ }
148
+
149
+ function collectFileWatcherChanges (
150
+ session : TestSession ,
151
+ file : string ,
152
+ eventType : "created" | "deleted" | "updated" ,
153
+ ) {
154
+ return collectWatchChanges (
155
+ session ,
156
+ ( session . logger . host as TestServerHostWithCustomWatch ) . factoryData . watchUtils . pollingWatches ,
157
+ file ,
158
+ file ,
159
+ eventType ,
160
+ ) ;
161
+ }
162
+
163
+ function invokeWatchChange (
164
+ session : TestSession ,
165
+ ...args : ( ts . server . protocol . WatchChangeRequestArgs [ ] | undefined ) [ ]
166
+ ) {
167
+ let result : Map < number , ts . server . protocol . WatchChangeRequestArgs > | undefined ;
168
+ args . forEach ( arg =>
169
+ arg ?. forEach ( value => {
170
+ result ??= new Map ( ) ;
171
+ const valueInResult = result . get ( value . id ) ;
172
+ if ( ! valueInResult ) result . set ( value . id , value ) ;
173
+ else {
174
+ valueInResult . created = ts . combine ( valueInResult . created , value . created ) ;
175
+ valueInResult . deleted = ts . combine ( valueInResult . deleted , value . deleted ) ;
176
+ valueInResult . updated = ts . combine ( valueInResult . updated , value . updated ) ;
177
+ }
178
+ } )
179
+ ) ;
180
+ if ( result ) {
181
+ session . executeCommandSeq < ts . server . protocol . WatchChangeRequest > ( {
182
+ command : ts . server . protocol . CommandTypes . WatchChange ,
183
+ arguments : ts . singleOrMany ( ts . arrayFrom ( result . values ( ) ) ) ,
184
+ } ) ;
185
+ }
186
+ }
187
+
99
188
function addFile ( session : TestSession , path : string ) {
100
189
updateFileOnHost ( session , path , "Add file" ) ;
101
- session . logger . log ( "Custom watch" ) ;
102
- ( session . logger . host as TestServerHostWithCustomWatch ) . factoryData . watchUtils . fsWatchesRecursive . forEach (
103
- "/user/username/projects/myproject" ,
104
- data =>
105
- session . executeCommandSeq < ts . server . protocol . WatchChangeRequest > ( {
106
- command : ts . server . protocol . CommandTypes . WatchChange ,
107
- arguments : { id : data . id , path, eventType : "create" } ,
108
- } ) ,
190
+ invokeWatchChange (
191
+ session ,
192
+ collectDirectoryWatcherChanges ( session , "/user/username/projects/myproject" , path , "created" ) ,
109
193
) ;
110
194
session . host . runQueuedTimeoutCallbacks ( ) ;
111
195
}
112
196
113
- function changeFile ( session : TestSession , path : string ) {
114
- updateFileOnHost ( session , path , "Change File" ) ;
115
- session . logger . log ( "Custom watch" ) ;
116
- ( session . logger . host as TestServerHostWithCustomWatch ) . factoryData . watchUtils . pollingWatches . forEach (
117
- path ,
118
- data =>
119
- session . executeCommandSeq < ts . server . protocol . WatchChangeRequest > ( {
120
- command : ts . server . protocol . CommandTypes . WatchChange ,
121
- arguments : { id : data . id , path, eventType : "update" } ,
122
- } ) ,
197
+ function changeFile ( session : TestSession , path : string , content ?: string ) {
198
+ updateFileOnHost ( session , path , "Change File" , content ) ;
199
+ invokeWatchChange (
200
+ session ,
201
+ collectFileWatcherChanges ( session , path , "updated" ) ,
202
+ collectDirectoryWatcherChanges ( session , ts . getDirectoryPath ( path ) , path , "updated" ) ,
203
+ ) ;
204
+ session . host . runQueuedTimeoutCallbacks ( ) ;
205
+ }
206
+
207
+ function npmInstall ( session : TestSession ) {
208
+ session . logger . log ( "update with npm install" ) ;
209
+ session . host . appendFile ( "/user/username/projects/myproject/node_modules/something/index.d.ts" , `export const y = 20;` ) ;
210
+ session . host . runQueuedTimeoutCallbacks ( ) ;
211
+ invokeWatchChange (
212
+ session ,
213
+ collectDirectoryWatcherChanges (
214
+ session ,
215
+ "/user/username/projects/myproject/node_modules" ,
216
+ "/user/username/projects/myproject/node_modules/something/index.d.ts" ,
217
+ "updated" ,
218
+ ) ,
123
219
) ;
124
220
session . host . runQueuedTimeoutCallbacks ( ) ;
125
221
}
@@ -129,6 +225,8 @@ describe("unittests:: tsserver:: events:: watchEvents", () => {
129
225
"/user/username/projects/myproject/tsconfig.json" : "{}" ,
130
226
"/user/username/projects/myproject/a.ts" : `export class a { prop = "hello"; foo() { return this.prop; } }` ,
131
227
"/user/username/projects/myproject/b.ts" : `export class b { prop = "hello"; foo() { return this.prop; } }` ,
228
+ "/user/username/projects/myproject/m.ts" : `import { x } from "something"` ,
229
+ "/user/username/projects/myproject/node_modules/something/index.d.ts" : `export const x = 10;` ,
132
230
[ libFile . path ] : libFile . content ,
133
231
} ) ;
134
232
const logger = createLoggerWithInMemoryLogs ( inputHost ) ;
@@ -153,6 +251,26 @@ describe("unittests:: tsserver:: events:: watchEvents", () => {
153
251
// Re watch
154
252
closeFilesForSession ( [ "/user/username/projects/myproject/b.ts" ] , session ) ;
155
253
254
+ // Update c.ts
255
+ changeFile ( session , "/user/username/projects/myproject/c.ts" , `export const y = 20;` ) ;
256
+
257
+ // Update with npm install
258
+ npmInstall ( session ) ;
259
+ host . runQueuedTimeoutCallbacks ( ) ;
260
+
261
+ // Add and change multiple files - combine and send multiple requests together
262
+ updateFileOnHost ( session , "/user/username/projects/myproject/d.ts" , "Add file" ) ;
263
+ updateFileOnHost ( session , "/user/username/projects/myproject/c.ts" , "Change File" , `export const z = 30;` ) ;
264
+ updateFileOnHost ( session , "/user/username/projects/myproject/e.ts" , "Add File" ) ;
265
+ invokeWatchChange (
266
+ session ,
267
+ collectDirectoryWatcherChanges ( session , "/user/username/projects/myproject" , "/user/username/projects/myproject/d.ts" , "created" ) ,
268
+ collectFileWatcherChanges ( session , "/user/username/projects/myproject/c.ts" , "updated" ) ,
269
+ collectDirectoryWatcherChanges ( session , "/user/username/projects/myproject" , "/user/username/projects/myproject/c.ts" , "updated" ) ,
270
+ collectDirectoryWatcherChanges ( session , "/user/username/projects/myproject" , "/user/username/projects/myproject/e.ts" , "created" ) ,
271
+ ) ;
272
+ session . host . runQueuedTimeoutCallbacks ( ) ;
273
+
156
274
baselineTsserverLogs ( "events/watchEvents" , `canUseWatchEvents` , session ) ;
157
275
function handleWatchEvents ( event : ts . server . ProjectServiceEvent ) {
158
276
switch ( event . eventName ) {
@@ -192,9 +310,15 @@ describe("unittests:: tsserver:: events:: watchEvents", () => {
192
310
logger . msg = ( s , type ) => logger . info ( `${ type } :: ${ s } ` ) ;
193
311
session . executeCommandSeq < ts . server . protocol . WatchChangeRequest > ( {
194
312
command : ts . server . protocol . CommandTypes . WatchChange ,
195
- arguments : { id : 1 , path : "/user/username/projects/myproject/b.ts" , eventType : "update" } ,
313
+ arguments : { id : 1 , updated : [ "/user/username/projects/myproject/b.ts" ] } ,
196
314
} ) ;
197
315
316
+ // Update c.ts
317
+ changeFile ( session , "/user/username/projects/myproject/c.ts" , `export const y = 20;` ) ;
318
+
319
+ // Update with npm install
320
+ npmInstall ( session ) ;
321
+
198
322
baselineTsserverLogs ( "events/watchEvents" , `canUseWatchEvents without canUseEvents` , session ) ;
199
323
} ) ;
200
324
} ) ;
0 commit comments