@@ -210,7 +210,6 @@ export class Session {
210
210
// (because language service was disabled while waiting for ngcc).
211
211
// First, make sure the Angular project is complete.
212
212
this . runGlobalAnalysisForNewlyLoadedProject ( project ) ;
213
- project . refreshDiagnostics ( ) ; // Show initial diagnostics
214
213
}
215
214
216
215
/**
@@ -222,8 +221,15 @@ export class Session {
222
221
return ;
223
222
}
224
223
const fileName = project . getRootScriptInfos ( ) [ 0 ] . fileName ;
224
+ const label = `Global analysis - getSemanticDiagnostics for ${ fileName } ` ;
225
+ if ( isDebugMode ) {
226
+ console . time ( label ) ;
227
+ }
225
228
// Getting semantic diagnostics will trigger a global analysis.
226
229
project . getLanguageService ( ) . getSemanticDiagnostics ( fileName ) ;
230
+ if ( isDebugMode ) {
231
+ console . timeEnd ( label ) ;
232
+ }
227
233
}
228
234
229
235
private handleCompilerOptionsDiagnostics ( project : ts . server . Project ) {
@@ -279,7 +285,7 @@ export class Session {
279
285
case ts . server . ProjectsUpdatedInBackgroundEvent :
280
286
// ProjectsUpdatedInBackgroundEvent is sent whenever diagnostics are
281
287
// requested via project.refreshDiagnostics()
282
- this . triggerDiagnostics ( event . data . openFiles ) ;
288
+ this . triggerDiagnostics ( event . data . openFiles , event . eventName ) ;
283
289
break ;
284
290
case ts . server . ProjectLanguageServiceStateEvent :
285
291
this . connection . sendNotification ( ProjectLanguageService , {
@@ -290,12 +296,40 @@ export class Session {
290
296
}
291
297
292
298
/**
293
- * Retrieve Angular diagnostics for the specified `openFiles` after a specific
299
+ * Request diagnostics to be computed due to the specified `file` being opened
300
+ * or changed.
301
+ * @param file File opened / changed
302
+ * @param reason Trace to explain why diagnostics are requested
303
+ */
304
+ private requestDiagnosticsOnOpenOrChangeFile ( file : string , reason : string ) : void {
305
+ const files : string [ ] = [ ] ;
306
+ if ( isExternalTemplate ( file ) ) {
307
+ // If only external template is opened / changed, we know for sure it will
308
+ // not affect other files because it is local to the Component.
309
+ files . push ( file ) ;
310
+ } else {
311
+ // Get all open files. Cast is needed because the key of the map is
312
+ // actually ts.Path. See
313
+ // https://github.com/microsoft/TypeScript/blob/496a1d3caa21c762daa95b1ac1b75823f8774575/src/server/editorServices.ts#L978
314
+ const openFiles = toArray ( this . projectService . openFiles . keys ( ) ) as ts . Path [ ] ;
315
+ for ( const openFile of openFiles ) {
316
+ const scriptInfo = this . projectService . getScriptInfoForPath ( openFile ) ;
317
+ if ( scriptInfo ) {
318
+ files . push ( scriptInfo . fileName ) ;
319
+ }
320
+ }
321
+ }
322
+ this . triggerDiagnostics ( files , reason ) ;
323
+ }
324
+
325
+ /**
326
+ * Retrieve Angular diagnostics for the specified `files` after a specific
294
327
* `delay`, or renew the request if there's already a pending one.
295
- * @param openFiles
328
+ * @param files files to be checked
329
+ * @param reason Trace to explain why diagnostics are triggered
296
330
* @param delay time to wait before sending request (milliseconds)
297
331
*/
298
- private triggerDiagnostics ( openFiles : string [ ] , delay : number = 300 ) {
332
+ private triggerDiagnostics ( files : string [ ] , reason : string , delay : number = 300 ) {
299
333
// Do not immediately send a diagnostics request. Send only after user has
300
334
// stopped typing after the specified delay.
301
335
if ( this . diagnosticsTimeout ) {
@@ -305,24 +339,25 @@ export class Session {
305
339
// Set a new timeout
306
340
this . diagnosticsTimeout = setTimeout ( ( ) => {
307
341
this . diagnosticsTimeout = null ; // clear the timeout
308
- this . sendPendingDiagnostics ( openFiles ) ;
342
+ this . sendPendingDiagnostics ( files , reason ) ;
309
343
// Default delay is 200ms, consistent with TypeScript. See
310
344
// https://github.com/microsoft/vscode/blob/7b944a16f52843b44cede123dd43ae36c0405dfd/extensions/typescript-language-features/src/features/bufferSyncSupport.ts#L493)
311
345
} , delay ) ;
312
346
}
313
347
314
348
/**
315
- * Execute diagnostics request for each of the specified `openFiles`.
316
- * @param openFiles
349
+ * Execute diagnostics request for each of the specified `files`.
350
+ * @param files files to be checked
351
+ * @param reason Trace to explain why diagnostics is triggered
317
352
*/
318
- private async sendPendingDiagnostics ( openFiles : string [ ] ) {
319
- for ( let i = 0 ; i < openFiles . length ; ++ i ) {
320
- const fileName = openFiles [ i ] ;
353
+ private async sendPendingDiagnostics ( files : string [ ] , reason : string ) {
354
+ for ( let i = 0 ; i < files . length ; ++ i ) {
355
+ const fileName = files [ i ] ;
321
356
const result = this . getLSAndScriptInfo ( fileName ) ;
322
357
if ( ! result ) {
323
358
continue ;
324
359
}
325
- const label = `getSemanticDiagnostics - ${ fileName } ` ;
360
+ const label = `${ reason } - getSemanticDiagnostics for ${ fileName } ` ;
326
361
if ( isDebugMode ) {
327
362
console . time ( label ) ;
328
363
}
@@ -341,7 +376,7 @@ export class Session {
341
376
// so stop this one immediately.
342
377
return ;
343
378
}
344
- if ( i < openFiles . length - 1 ) {
379
+ if ( i < files . length - 1 ) {
345
380
// If this is not the last file, yield so that pending I/O events get a
346
381
// chance to run. This will open an opportunity for the server to process
347
382
// incoming requests. The next file will be checked in the next iteration
@@ -447,7 +482,8 @@ export class Session {
447
482
return ;
448
483
}
449
484
if ( project . languageServiceEnabled ) {
450
- project . refreshDiagnostics ( ) ; // Show initial diagnostics
485
+ // Show initial diagnostics
486
+ this . requestDiagnosticsOnOpenOrChangeFile ( filePath , `Opening ${ filePath } ` ) ;
451
487
}
452
488
} catch ( error ) {
453
489
if ( this . isProjectLoading ) {
@@ -540,7 +576,7 @@ export class Session {
540
576
if ( ! project || ! project . languageServiceEnabled ) {
541
577
return ;
542
578
}
543
- project . refreshDiagnostics ( ) ;
579
+ this . requestDiagnosticsOnOpenOrChangeFile ( scriptInfo . fileName , `Changing ${ filePath } ` ) ;
544
580
}
545
581
546
582
private onDidSaveTextDocument ( params : lsp . DidSaveTextDocumentParams ) {
@@ -988,3 +1024,11 @@ function isExternalAngularCore(path: string): boolean {
988
1024
function isInternalAngularCore ( path : string ) : boolean {
989
1025
return path . endsWith ( 'angular2/rc/packages/core/index.d.ts' ) ;
990
1026
}
1027
+
1028
+ function isTypeScriptFile ( path : string ) : boolean {
1029
+ return path . endsWith ( '.ts' ) ;
1030
+ }
1031
+
1032
+ function isExternalTemplate ( path : string ) : boolean {
1033
+ return ! isTypeScriptFile ( path ) ;
1034
+ }
0 commit comments