@@ -22,6 +22,7 @@ export interface SessionOptions {
22
22
logger : Logger ;
23
23
ngPlugin : string ;
24
24
ngProbeLocation : string ;
25
+ ivy : boolean ;
25
26
}
26
27
27
28
enum LanguageId {
@@ -40,11 +41,13 @@ export class Session {
40
41
private readonly connection : lsp . IConnection ;
41
42
private readonly projectService : ts . server . ProjectService ;
42
43
private readonly logger : Logger ;
44
+ private readonly ivy : boolean ;
43
45
private diagnosticsTimeout : NodeJS . Timeout | null = null ;
44
46
private isProjectLoading = false ;
45
47
46
48
constructor ( options : SessionOptions ) {
47
49
this . logger = options . logger ;
50
+ this . ivy = options . ivy ;
48
51
// Create a connection for the server. The connection uses Node's IPC as a transport.
49
52
this . connection = lsp . createConnection ( ) ;
50
53
this . addProtocolHandlers ( this . connection ) ;
@@ -102,6 +105,27 @@ export class Session {
102
105
conn . onTypeDefinition ( p => this . onTypeDefinition ( p ) ) ;
103
106
conn . onHover ( p => this . onHover ( p ) ) ;
104
107
conn . onCompletion ( p => this . onCompletion ( p ) ) ;
108
+ conn . onNotification ( notification . NgccComplete , p => this . handleNgccNotification ( p ) ) ;
109
+ }
110
+
111
+ private handleNgccNotification ( params : notification . NgccCompleteParams ) {
112
+ const { configFilePath} = params ;
113
+ if ( ! params . success ) {
114
+ this . error (
115
+ `Failed to run ngcc for ${ configFilePath } :\n` +
116
+ `${ params . error } \n` +
117
+ `Language service will remain disabled.` ) ;
118
+ return ;
119
+ }
120
+ const project = this . projectService . findProject ( configFilePath ) ;
121
+ if ( ! project ) {
122
+ this . error (
123
+ `Failed to find project for ${ configFilePath } returned by ngcc.\n` +
124
+ `Language service will remain disabled.` ) ;
125
+ return ;
126
+ }
127
+ project . enableLanguageService ( ) ;
128
+ this . info ( `Enabling Ivy language service for ${ project . projectName } .` ) ;
105
129
}
106
130
107
131
/**
@@ -118,23 +142,23 @@ export class Session {
118
142
this . logger . info ( `Loading new project: ${ event . data . reason } ` ) ;
119
143
break ;
120
144
case ts . server . ProjectLoadingFinishEvent : {
121
- const { project} = event . data ;
122
- try {
123
- // Disable language service if project is not Angular
124
- this . checkIsAngularProject ( project ) ;
125
- } finally {
126
- if ( this . isProjectLoading ) {
127
- this . isProjectLoading = false ;
128
- this . connection . sendNotification ( notification . ProjectLoadingFinish ) ;
129
- }
145
+ if ( this . isProjectLoading ) {
146
+ this . isProjectLoading = false ;
147
+ this . connection . sendNotification ( notification . ProjectLoadingFinish ) ;
130
148
}
149
+ this . checkProject ( event . data . project ) ;
131
150
break ;
132
151
}
133
152
case ts . server . ProjectsUpdatedInBackgroundEvent :
134
153
// ProjectsUpdatedInBackgroundEvent is sent whenever diagnostics are
135
154
// requested via project.refreshDiagnostics()
136
155
this . triggerDiagnostics ( event . data . openFiles ) ;
137
156
break ;
157
+ case ts . server . ProjectLanguageServiceStateEvent :
158
+ this . connection . sendNotification ( notification . ProjectLanguageService , {
159
+ projectName : event . data . project . getProjectName ( ) ,
160
+ languageServiceEnabled : event . data . languageServiceEnabled ,
161
+ } ) ;
138
162
}
139
163
}
140
164
@@ -501,12 +525,10 @@ export class Session {
501
525
}
502
526
503
527
/**
504
- * Determine if the specified `project` is Angular, and disable the language
505
- * service if not.
506
- * @param project
528
+ * Disable the language service if the specified `project` is not Angular or
529
+ * Ivy mode is enabled.
507
530
*/
508
- private checkIsAngularProject ( project : ts . server . Project ) {
509
- const NG_CORE = '@angular/core/core.d.ts' ;
531
+ private checkProject ( project : ts . server . Project ) {
510
532
const { projectName} = project ;
511
533
if ( ! project . languageServiceEnabled ) {
512
534
this . info (
@@ -517,42 +539,51 @@ export class Session {
517
539
518
540
return ;
519
541
}
520
- if ( ! isAngularProject ( project , NG_CORE ) ) {
521
- project . disableLanguageService ( ) ;
522
- this . info (
523
- `Disabling language service for ${ projectName } because it is not an Angular project ` +
524
- `('${ NG_CORE } ' could not be found). ` +
525
- `If you believe you are seeing this message in error, please reinstall the packages in your package.json.` ) ;
526
-
527
- if ( project . getExcludedFiles ( ) . some ( f => f . endsWith ( NG_CORE ) ) ) {
528
- this . info (
529
- `Please check your tsconfig.json to make sure 'node_modules' directory is not excluded.` ) ;
530
- }
531
542
543
+ if ( ! this . checkIsAngularProject ( project ) ) {
532
544
return ;
533
545
}
534
546
535
- // The language service should be enabled at this point.
536
- this . info ( `Enabling language service for ${ projectName } .` ) ;
547
+ if ( this . ivy && project instanceof ts . server . ConfiguredProject ) {
548
+ // Keep language service disabled until ngcc is completed.
549
+ project . disableLanguageService ( ) ;
550
+ this . connection . sendNotification ( notification . RunNgcc , {
551
+ configFilePath : project . getConfigFilePath ( ) ,
552
+ } ) ;
553
+ } else {
554
+ // Immediately enable Legacy/ViewEngine language service
555
+ this . info ( `Enabling VE language service for ${ projectName } .` ) ;
556
+ }
537
557
}
538
- }
539
558
540
- /**
541
- * Return true if the specified `project` contains the Angular core declaration.
542
- * @param project
543
- * @param ngCore path that uniquely identifies `@angular/core`.
544
- */
545
- function isAngularProject ( project : ts . server . Project , ngCore : string ) : boolean {
546
- project . markAsDirty ( ) ; // Must mark project as dirty to rebuild the program.
547
- if ( project . isNonTsProject ( ) ) {
548
- return false ;
549
- }
550
- for ( const fileName of project . getFileNames ( ) ) {
551
- if ( fileName . endsWith ( ngCore ) ) {
559
+ /**
560
+ * Determine if the specified `project` is Angular, and disable the language
561
+ * service if not.
562
+ */
563
+ private checkIsAngularProject ( project : ts . server . Project ) : boolean {
564
+ const { projectName } = project ;
565
+ const NG_CORE = '@angular/core/core.d.ts' ;
566
+
567
+ const isAngularProject = project . hasRoots ( ) && ! project . isNonTsProject ( ) &&
568
+ project . getFileNames ( ) . some ( f => f . endsWith ( NG_CORE ) ) ;
569
+
570
+ if ( isAngularProject ) {
552
571
return true ;
553
572
}
573
+
574
+ project . disableLanguageService ( ) ;
575
+ this . info (
576
+ `Disabling language service for ${ projectName } because it is not an Angular project ` +
577
+ `('${ NG_CORE } ' could not be found). ` +
578
+ `If you believe you are seeing this message in error, please reinstall the packages in your package.json.` ) ;
579
+
580
+ if ( project . getExcludedFiles ( ) . some ( f => f . endsWith ( NG_CORE ) ) ) {
581
+ this . info (
582
+ `Please check your tsconfig.json to make sure 'node_modules' directory is not excluded.` ) ;
583
+ }
584
+
585
+ return false ;
554
586
}
555
- return false ;
556
587
}
557
588
558
589
function isConfiguredProject ( project : ts . server . Project ) : project is ts . server . ConfiguredProject {
0 commit comments