mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(compiler-cli): catch fatal diagnostic when getting diagnostics for components (#50046)
This commit adds similar handling to what was done in https://github.com/angular/angular/commit/ed817e32fe0239c0f08ce342c7ad224055d56f84. The language service calls the `getDiagnosticsForComponent` function when the file is not a typescript file. fixes https://github.com/angular/vscode-ng-language-service/issues/1881 PR Close #50046
This commit is contained in:
committed by
Pawel Kozlowski
parent
c650b40816
commit
ce00738f98
@@ -448,11 +448,18 @@ export class NgCompiler {
|
||||
const compilation = this.ensureAnalyzed();
|
||||
const ttc = compilation.templateTypeChecker;
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
diagnostics.push(...ttc.getDiagnosticsForComponent(component));
|
||||
try {
|
||||
diagnostics.push(...ttc.getDiagnosticsForComponent(component));
|
||||
|
||||
const extendedTemplateChecker = compilation.extendedTemplateChecker;
|
||||
if (this.options.strictTemplates && extendedTemplateChecker) {
|
||||
diagnostics.push(...extendedTemplateChecker.getDiagnosticsForComponent(component));
|
||||
const extendedTemplateChecker = compilation.extendedTemplateChecker;
|
||||
if (this.options.strictTemplates && extendedTemplateChecker) {
|
||||
diagnostics.push(...extendedTemplateChecker.getDiagnosticsForComponent(component));
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (!(err instanceof FatalDiagnosticError)) {
|
||||
throw err;
|
||||
}
|
||||
diagnostics.push(err.toDiagnostic());
|
||||
}
|
||||
return this.addMessageTextDetails(diagnostics);
|
||||
}
|
||||
|
||||
@@ -492,6 +492,49 @@ describe('getSemanticDiagnostics', () => {
|
||||
const diags = project.getDiagnosticsForFile('app.html');
|
||||
expect(diags.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('generates diagnostic when the library does not export the host directive', () => {
|
||||
const files = {
|
||||
// export post module and component but not the host directive. This is not valid. We won't
|
||||
// be able to import the host directive for template type checking.
|
||||
'dist/post/index.d.ts': `
|
||||
export { PostComponent, PostModule } from './lib/post.component';
|
||||
`,
|
||||
'dist/post/lib/post.component.d.ts': `
|
||||
import * as i0 from "@angular/core";
|
||||
export declare class HostBindDirective {
|
||||
static ɵdir: i0.ɵɵDirectiveDeclaration<HostBindDirective, never, never, {}, {}, never, never, true, never>;
|
||||
}
|
||||
export declare class PostComponent {
|
||||
static ɵcmp: i0.ɵɵComponentDeclaration<PostComponent, "lib-post", never, {}, {}, never, never, false, [{ directive: typeof HostBindDirective; inputs: {}; outputs: {}; }]>;
|
||||
}
|
||||
export declare class PostModule {
|
||||
static ɵmod: i0.ɵɵNgModuleDeclaration<PostModule, [typeof PostComponent], never, [typeof PostComponent]>;
|
||||
static ɵinj: i0.ɵɵInjectorDeclaration<PostModule>;
|
||||
}
|
||||
`,
|
||||
'test.ts': `
|
||||
import {Component} from '@angular/core';
|
||||
import {PostModule} from 'post';
|
||||
|
||||
@Component({
|
||||
templateUrl: './test.ng.html',
|
||||
imports: [PostModule],
|
||||
standalone: true,
|
||||
})
|
||||
export class Main { }
|
||||
`,
|
||||
'test.ng.html': '<lib-post />'
|
||||
};
|
||||
|
||||
const tsCompilerOptions = {paths: {'post': ['dist/post']}};
|
||||
const project = env.addProject('test', files, {}, tsCompilerOptions);
|
||||
|
||||
const diags = project.getDiagnosticsForFile('test.ng.html');
|
||||
expect(diags.length).toBe(1);
|
||||
expect(ts.flattenDiagnosticMessageText(diags[0].messageText, ''))
|
||||
.toContain('HostBindDirective');
|
||||
});
|
||||
});
|
||||
|
||||
function getTextOfDiagnostic(diag: ts.Diagnostic): string {
|
||||
|
||||
@@ -48,12 +48,15 @@ export class LanguageServiceTestEnv {
|
||||
|
||||
constructor(private host: MockServerHost, private projectService: ts.server.ProjectService) {}
|
||||
|
||||
addProject(name: string, files: ProjectFiles, options: TestableOptions = {}): Project {
|
||||
addProject(
|
||||
name: string, files: ProjectFiles, angularCompilerOptions: TestableOptions = {},
|
||||
tsCompilerOptions = {}): Project {
|
||||
if (this.projects.has(name)) {
|
||||
throw new Error(`Project ${name} is already defined`);
|
||||
}
|
||||
|
||||
const project = Project.initialize(name, this.projectService, files, options);
|
||||
const project = Project.initialize(
|
||||
name, this.projectService, files, angularCompilerOptions, tsCompilerOptions);
|
||||
this.projects.set(name, project);
|
||||
return project;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export type ProjectFiles = {
|
||||
|
||||
function writeTsconfig(
|
||||
fs: FileSystem, tsConfigPath: AbsoluteFsPath, entryFiles: AbsoluteFsPath[],
|
||||
options: TestableOptions): void {
|
||||
angularCompilerOptions: TestableOptions, tsCompilerOptions: {}): void {
|
||||
fs.writeFile(
|
||||
tsConfigPath,
|
||||
JSON.stringify(
|
||||
@@ -36,11 +36,12 @@ function writeTsconfig(
|
||||
'dom',
|
||||
'es2015',
|
||||
],
|
||||
...tsCompilerOptions,
|
||||
},
|
||||
files: entryFiles,
|
||||
angularCompilerOptions: {
|
||||
strictTemplates: true,
|
||||
...options,
|
||||
...angularCompilerOptions,
|
||||
}
|
||||
},
|
||||
null, 2));
|
||||
@@ -57,7 +58,7 @@ export class Project {
|
||||
|
||||
static initialize(
|
||||
projectName: string, projectService: ts.server.ProjectService, files: ProjectFiles,
|
||||
options: TestableOptions = {}): Project {
|
||||
angularCompilerOptions: TestableOptions = {}, tsCompilerOptions = {}): Project {
|
||||
const fs = getFileSystem();
|
||||
const tsConfigPath = absoluteFrom(`/${projectName}/tsconfig.json`);
|
||||
|
||||
@@ -73,7 +74,7 @@ export class Project {
|
||||
}
|
||||
}
|
||||
|
||||
writeTsconfig(fs, tsConfigPath, entryFiles, options);
|
||||
writeTsconfig(fs, tsConfigPath, entryFiles, angularCompilerOptions, tsCompilerOptions);
|
||||
|
||||
// Ensure the project is live in the ProjectService.
|
||||
projectService.openClientFile(entryFiles[0]);
|
||||
|
||||
@@ -49,7 +49,7 @@ function getFirstClassDeclaration(declaration: string) {
|
||||
|
||||
export function createModuleAndProjectWithDeclarations(
|
||||
env: LanguageServiceTestEnv, projectName: string, projectFiles: ProjectFiles,
|
||||
options: TestableOptions = {}, standaloneFiles: ProjectFiles = {}): Project {
|
||||
angularCompilerOptions: TestableOptions = {}, standaloneFiles: ProjectFiles = {}): Project {
|
||||
const externalClasses: string[] = [];
|
||||
const externalImports: string[] = [];
|
||||
for (const [fileName, fileContents] of Object.entries(projectFiles)) {
|
||||
@@ -72,7 +72,7 @@ export function createModuleAndProjectWithDeclarations(
|
||||
export class AppModule {}
|
||||
`;
|
||||
projectFiles['app-module.ts'] = moduleContents;
|
||||
return env.addProject(projectName, {...projectFiles, ...standaloneFiles}, options);
|
||||
return env.addProject(projectName, {...projectFiles, ...standaloneFiles}, angularCompilerOptions);
|
||||
}
|
||||
|
||||
export function humanizeDocumentSpanLike<T extends ts.DocumentSpan>(
|
||||
|
||||
Reference in New Issue
Block a user