fix(language-service): Recover from error in analyzing Ng Modules (#37108)
In place of failing to return analyzed Ng Modules when the analyzer fails, return the previously-analyzed Ng Modules (which may be empty) and log an error. Closes https://github.com/angular/vscode-ng-language-service/issues/777 PR Close #37108
This commit is contained in:
parent
34827559b9
commit
c4f4675ebf
|
@ -175,8 +175,15 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
|
|||
}
|
||||
};
|
||||
const programFiles = this.program.getSourceFiles().map(sf => sf.fileName);
|
||||
this.analyzedModules =
|
||||
analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver);
|
||||
|
||||
try {
|
||||
this.analyzedModules =
|
||||
analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver);
|
||||
} catch (e) {
|
||||
// Analyzing modules may throw; in that case, reuse the old modules.
|
||||
this.error(`Analyzing NgModules failed. ${e}`);
|
||||
return this.analyzedModules;
|
||||
}
|
||||
|
||||
// update template references and fileToComponent
|
||||
const urlResolver = createOfflineCompileUrlResolver();
|
||||
|
|
|
@ -101,6 +101,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
|||
private readonly overrideDirectory = new Set<string>();
|
||||
private readonly existsCache = new Map<string, boolean>();
|
||||
private readonly fileCache = new Map<string, string|undefined>();
|
||||
errors: string[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly scriptNames: string[],
|
||||
|
@ -398,6 +399,10 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
|||
}
|
||||
throw new Error(`Failed to find marker '${selector}' in ${fileName}`);
|
||||
}
|
||||
|
||||
error(msg: string) {
|
||||
this.errors.push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
const locationMarker = /\~\{(\w+(-\w+)*)\}/g;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import * as ngc from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {TypeScriptServiceHost} from '../src/typescript_host';
|
||||
|
@ -216,4 +217,44 @@ describe('TypeScriptServiceHost', () => {
|
|||
// But the content should be exactly the same
|
||||
expect(newModules).toEqual(oldModules);
|
||||
});
|
||||
|
||||
it('should recover from error in analyzing ng modules', () => {
|
||||
// First create a TypescriptHost with empty script names
|
||||
const tsLSHost = new MockTypescriptHost([]);
|
||||
const tsLS = ts.createLanguageService(tsLSHost);
|
||||
const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
|
||||
const oldModules = ngLSHost.getAnalyzedModules();
|
||||
expect(oldModules.ngModules).toEqual([]);
|
||||
// Now add a script, this would change the program
|
||||
let fileName = '/app/main.ts';
|
||||
let content = `
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
entryComponents: [CommonModule],
|
||||
})
|
||||
export class AppModule {}
|
||||
`;
|
||||
tsLSHost.addScript(fileName, content);
|
||||
|
||||
// If analyzing modules throws, the old modules should be returned.
|
||||
let newModules = ngLSHost.getAnalyzedModules();
|
||||
expect(newModules.ngModules).toEqual([]);
|
||||
expect(tsLSHost.errors).toEqual([
|
||||
'Analyzing NgModules failed. Error: CommonModule cannot be used as an entry component.'
|
||||
]);
|
||||
|
||||
content = `
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({})
|
||||
export class AppModule {}
|
||||
`;
|
||||
tsLSHost.override(fileName, content);
|
||||
// Check that analyzing modules successfully still works.
|
||||
newModules = ngLSHost.getAnalyzedModules();
|
||||
expect(newModules.ngModules.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue