@@ -160,63 +160,23 @@ export class Session {
160
160
} ;
161
161
}
162
162
163
- private async runNgcc ( configFilePath : string ) {
164
- this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
165
- done : false ,
166
- configFilePath,
167
- message : `Running ngcc for project ${ configFilePath } ` ,
168
- } ) ;
169
-
170
- let success = false ;
171
-
172
- try {
173
- await resolveAndRunNgcc ( configFilePath , {
174
- report : ( msg : string ) => {
175
- this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
176
- done : false ,
177
- configFilePath,
178
- message : msg ,
179
- } ) ;
180
- } ,
181
- } ) ;
182
- success = true ;
183
- } catch ( e ) {
184
- this . error (
185
- `Failed to run ngcc for ${ configFilePath } :\n` +
186
- ` ${ e . message } \n` +
187
- ` Language service will remain disabled.` ) ;
188
- } finally {
189
- this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
190
- done : true ,
191
- configFilePath,
192
- success,
193
- } ) ;
194
- }
195
-
196
- // Re-enable language service even if ngcc fails, because users could fix
197
- // the problem by running ngcc themselves. If we keep language service
198
- // disabled, there's no way users could use the extension even after
199
- // resolving ngcc issues. On the client side, we will warn users about
200
- // potentially degraded experience.
201
-
202
- this . reenableLanguageServiceForProject ( configFilePath ) ;
203
- }
204
-
205
- private reenableLanguageServiceForProject ( configFilePath : string ) {
206
- const project = this . projectService . findProject ( configFilePath ) ;
207
- if ( ! project ) {
208
- this . error (
209
- `Failed to find project for ${ configFilePath } returned by ngcc.\n` +
210
- `Language service will remain disabled.` ) ;
163
+ private enableLanguageServiceForProject ( project : ts . server . Project , angularCore : string ) {
164
+ const { projectName} = project ;
165
+ if ( ! project . languageServiceEnabled ) {
166
+ project . enableLanguageService ( ) ;
167
+ // When the language service got disabled, the program was discarded via
168
+ // languageService.cleanupSemanticCache(). However, the program is not
169
+ // recreated when the language service is re-enabled. We manually mark the
170
+ // project as dirty to force update the graph.
171
+ project . markAsDirty ( ) ;
172
+ }
173
+ if ( ! this . ivy ) {
174
+ // Immediately enable Legacy / View Engine language service
175
+ this . info ( `Enabling View Engine language service for ${ projectName } .` ) ;
176
+ this . promptToEnableIvyIfAvailable ( project , angularCore ) ;
211
177
return ;
212
178
}
213
- project . enableLanguageService ( ) ;
214
- // When the language service got disabled, the program was discarded via
215
- // languageService.cleanupSemanticCache(). However, the program is not
216
- // recreated when the language service is re-enabled. We manually mark the
217
- // project as dirty to force update the graph.
218
- project . markAsDirty ( ) ;
219
- this . info ( `Enabling Ivy language service for ${ project . projectName } .` ) ;
179
+ this . info ( `Enabling Ivy language service for ${ projectName } .` ) ;
220
180
this . handleCompilerOptionsDiagnostics ( project ) ;
221
181
// Send diagnostics since we skipped this step when opening the file
222
182
// (because language service was disabled while waiting for ngcc).
@@ -276,7 +236,16 @@ export class Session {
276
236
this . isProjectLoading = false ;
277
237
this . connection . sendNotification ( ProjectLoadingFinish ) ;
278
238
}
279
- this . checkProject ( event . data . project ) ;
239
+ const { project} = event . data ;
240
+ const angularCore = this . findAngularCoreOrDisableLanguageService ( project ) ;
241
+ if ( angularCore ) {
242
+ if ( this . ivy && isExternalAngularCore ( angularCore ) ) {
243
+ // Do not wait on this promise otherwise we'll be blocking other requests
244
+ this . runNgcc ( project , angularCore ) ;
245
+ } else {
246
+ this . enableLanguageServiceForProject ( project , angularCore ) ;
247
+ }
248
+ }
280
249
break ;
281
250
}
282
251
case ts . server . ProjectsUpdatedInBackgroundEvent :
@@ -853,42 +822,91 @@ export class Session {
853
822
}
854
823
855
824
/**
856
- * Disable the language service if the specified `project` is not Angular or
857
- * Ivy mode is enabled.
825
+ * Find the main declaration file for `@angular/core` in the specified
826
+ * `project`. If found, return the declaration file. Otherwise, disable the
827
+ * language service and return undefined.
828
+ *
829
+ * @returns main declaration file in `@angular/core`.
858
830
*/
859
- private checkProject ( project : ts . server . Project ) {
831
+ private findAngularCoreOrDisableLanguageService ( project : ts . server . Project ) : string | undefined {
860
832
const { projectName} = project ;
861
833
if ( ! project . languageServiceEnabled ) {
862
834
this . info (
863
835
`Language service is already disabled for ${ projectName } . ` +
864
836
`This could be due to non-TS files that exceeded the size limit (${
865
837
ts . server . maxProgramSizeForNonTsFiles } bytes).` +
866
838
`Please check log file for details.` ) ;
867
-
868
839
return ;
869
840
}
841
+ if ( ! project . hasRoots ( ) || project . isNonTsProject ( ) ) {
842
+ return undefined ;
843
+ }
844
+ const angularCore = project . getFileNames ( ) . find ( isAngularCore ) ;
845
+ if ( angularCore === undefined ) {
846
+ project . disableLanguageService ( ) ;
847
+ this . info (
848
+ `Disabling language service for ${ projectName } because it is not an Angular project ` +
849
+ `('@angular/core' could not be found).` ) ;
850
+ if ( project . getExcludedFiles ( ) . some ( isAngularCore ) ) {
851
+ this . info (
852
+ `Please check your tsconfig.json to make sure 'node_modules' directory is not excluded.` ) ;
853
+ }
854
+ }
855
+ return angularCore ;
856
+ }
870
857
871
- const coreDts = this . checkIsAngularProject ( project ) ;
872
- if ( coreDts === undefined ) {
858
+ /**
859
+ * Disable the language service, run ngcc, then re-enable language service.
860
+ */
861
+ private async runNgcc ( project : ts . server . Project , angularCore : string ) : Promise < void > {
862
+ if ( ! isConfiguredProject ( project ) ) {
873
863
return ;
874
864
}
865
+ // Disable language service until ngcc is completed.
866
+ project . disableLanguageService ( ) ;
867
+ const configFilePath = project . getConfigFilePath ( ) ;
875
868
876
- if ( this . ivy && isConfiguredProject ( project ) ) {
877
- // Keep language service disabled until ngcc is completed.
878
- project . disableLanguageService ( ) ;
879
- // Do not wait on this promise otherwise we'll be blocking other requests
880
- this . runNgcc ( project . getConfigFilePath ( ) ) . catch ( ( error : Error ) => {
881
- this . error ( error . toString ( ) ) ;
869
+ this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
870
+ done : false ,
871
+ configFilePath,
872
+ message : `Running ngcc for ${ configFilePath } ` ,
873
+ } ) ;
874
+
875
+ let success = false ;
876
+
877
+ try {
878
+ await resolveAndRunNgcc ( configFilePath , {
879
+ report : ( msg : string ) => {
880
+ this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
881
+ done : false ,
882
+ configFilePath,
883
+ message : msg ,
884
+ } ) ;
885
+ } ,
886
+ } ) ;
887
+ success = true ;
888
+ } catch ( e ) {
889
+ this . error (
890
+ `Failed to run ngcc for ${ configFilePath } :\n` +
891
+ ` ${ e . message } \n` +
892
+ ` Language service will remain disabled.` ) ;
893
+ } finally {
894
+ this . connection . sendProgress ( NgccProgressType , NgccProgressToken , {
895
+ done : true ,
896
+ configFilePath,
897
+ success,
882
898
} ) ;
883
- } else {
884
- // Immediately enable Legacy/ViewEngine language service
885
- this . info ( `Enabling VE language service for ${ projectName } .` ) ;
886
- this . promptToEnableIvyIfAvailable ( project , coreDts ) ;
887
899
}
900
+
901
+ // Re-enable language service even if ngcc fails, because users could fix
902
+ // the problem by running ngcc themselves. If we keep language service
903
+ // disabled, there's no way users could use the extension even after
904
+ // resolving ngcc issues. On the client side, we will warn users about
905
+ // potentially degraded experience.
906
+ this . enableLanguageServiceForProject ( project , angularCore ) ;
888
907
}
889
908
890
- private promptToEnableIvyIfAvailable (
891
- project : ts . server . Project , coreDts : ts . server . NormalizedPath ) {
909
+ private promptToEnableIvyIfAvailable ( project : ts . server . Project , coreDts : string ) : void {
892
910
let angularCoreVersion = this . angularCoreVersionMap . get ( project ) ;
893
911
if ( angularCoreVersion === undefined ) {
894
912
angularCoreVersion = resolve ( '@angular/core' , coreDts ) ?. version ;
@@ -901,37 +919,6 @@ export class Session {
901
919
} ) ;
902
920
}
903
921
}
904
-
905
- /**
906
- * Determine if the specified `project` is Angular, and disable the language
907
- * service if not.
908
- *
909
- * @returns The `ts.server.NormalizedPath` to the `@angular/core/core.d.ts` file.
910
- */
911
- private checkIsAngularProject ( project : ts . server . Project ) : ts . server . NormalizedPath | undefined {
912
- const { projectName} = project ;
913
- const NG_CORE = '@angular/core/core.d.ts' ;
914
- const ngCoreDts = project . getFileNames ( ) . find ( f => f . endsWith ( NG_CORE ) ) ;
915
- const isAngularProject =
916
- project . hasRoots ( ) && ! project . isNonTsProject ( ) && ngCoreDts !== undefined ;
917
-
918
- if ( isAngularProject ) {
919
- return ngCoreDts ;
920
- }
921
-
922
- project . disableLanguageService ( ) ;
923
- this . info (
924
- `Disabling language service for ${ projectName } because it is not an Angular project ` +
925
- `('${ NG_CORE } ' could not be found). ` +
926
- `If you believe you are seeing this message in error, please reinstall the packages in your package.json.` ) ;
927
-
928
- if ( project . getExcludedFiles ( ) . some ( f => f . endsWith ( NG_CORE ) ) ) {
929
- this . info (
930
- `Please check your tsconfig.json to make sure 'node_modules' directory is not excluded.` ) ;
931
- }
932
-
933
- return undefined ;
934
- }
935
922
}
936
923
937
924
function toArray < T > ( it : ts . Iterator < T > ) : T [ ] {
@@ -942,6 +929,19 @@ function toArray<T>(it: ts.Iterator<T>): T[] {
942
929
return results ;
943
930
}
944
931
932
+ // TODO: Replace with `isNgLanguageService` from `@angular/language-service`.
945
933
function isNgLs ( ls : ts . LanguageService | NgLanguageService ) : ls is NgLanguageService {
946
934
return 'getTcb' in ls ;
947
- }
935
+ }
936
+
937
+ function isAngularCore ( path : string ) : boolean {
938
+ return isExternalAngularCore ( path ) || isInternalAngularCore ( path ) ;
939
+ }
940
+
941
+ function isExternalAngularCore ( path : string ) : boolean {
942
+ return path . endsWith ( '@angular/core/core.d.ts' ) ;
943
+ }
944
+
945
+ function isInternalAngularCore ( path : string ) : boolean {
946
+ return path . endsWith ( 'angular2/rc/packages/core/index.d.ts' ) ;
947
+ }
0 commit comments