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);
|
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
|
// update template references and fileToComponent
|
||||||
const urlResolver = createOfflineCompileUrlResolver();
|
const urlResolver = createOfflineCompileUrlResolver();
|
||||||
|
@ -101,6 +101,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
|||||||
private readonly overrideDirectory = new Set<string>();
|
private readonly overrideDirectory = new Set<string>();
|
||||||
private readonly existsCache = new Map<string, boolean>();
|
private readonly existsCache = new Map<string, boolean>();
|
||||||
private readonly fileCache = new Map<string, string|undefined>();
|
private readonly fileCache = new Map<string, string|undefined>();
|
||||||
|
errors: string[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly scriptNames: string[],
|
private readonly scriptNames: string[],
|
||||||
@ -398,6 +399,10 @@ export class MockTypescriptHost implements ts.LanguageServiceHost {
|
|||||||
}
|
}
|
||||||
throw new Error(`Failed to find marker '${selector}' in ${fileName}`);
|
throw new Error(`Failed to find marker '${selector}' in ${fileName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error(msg: string) {
|
||||||
|
this.errors.push(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const locationMarker = /\~\{(\w+(-\w+)*)\}/g;
|
const locationMarker = /\~\{(\w+(-\w+)*)\}/g;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as ngc from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {TypeScriptServiceHost} from '../src/typescript_host';
|
import {TypeScriptServiceHost} from '../src/typescript_host';
|
||||||
@ -216,4 +217,44 @@ describe('TypeScriptServiceHost', () => {
|
|||||||
// But the content should be exactly the same
|
// But the content should be exactly the same
|
||||||
expect(newModules).toEqual(oldModules);
|
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…
x
Reference in New Issue
Block a user