mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(compiler-cli): add extendedTemplateCheck phase to compiler (#43107)
This commit integrates extended template checks with the compiler, by adding another phase of diagnostics generation. This integration is under the `_extendedTemplateDiagnostics` flag. Refs #42966 PR Close #43107
This commit is contained in:
committed by
Alex Rickabaugh
parent
cb654d1c53
commit
ff858ac9d8
@@ -26,6 +26,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/transform",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/api",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"//packages/compiler-cli/src/ngtsc/xi18n",
|
||||
"@npm//@types/node",
|
||||
|
||||
@@ -24,6 +24,7 @@ import {ClassDeclaration, DeclarationNode, Decorator, ReflectionHost, reflectObj
|
||||
import {ComponentScopeReader, LocalModuleScopeRegistry, TypeCheckScopeRegistry} from '../../scope';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform';
|
||||
import {TemplateSourceMapping, TypeCheckContext} from '../../typecheck/api';
|
||||
import {ExtendedTemplateChecker} from '../../typecheck/extended/api';
|
||||
import {SubsetOfKeys} from '../../util/src/typescript';
|
||||
import {Xi18nContext} from '../../xi18n';
|
||||
|
||||
@@ -613,6 +614,12 @@ export class ComponentDecoratorHandler implements
|
||||
meta.template.sourceMapping, meta.template.file, meta.template.errors);
|
||||
}
|
||||
|
||||
extendedTemplateCheck(
|
||||
component: ts.ClassDeclaration,
|
||||
extendedTemplateChecker: ExtendedTemplateChecker): ts.Diagnostic[] {
|
||||
return extendedTemplateChecker.getExtendedTemplateDiagnosticsForComponent(component);
|
||||
}
|
||||
|
||||
resolve(
|
||||
node: ClassDeclaration, analysis: Readonly<ComponentAnalysisData>,
|
||||
symbol: ComponentSymbol): ResolveResult<ComponentResolutionData> {
|
||||
|
||||
@@ -37,6 +37,8 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/src/template_checks/invalid_banana_in_box",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"//packages/compiler-cli/src/ngtsc/xi18n",
|
||||
"@npm//typescript",
|
||||
|
||||
@@ -36,6 +36,16 @@ export interface TestOnlyOptions {
|
||||
tracePerformance?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal only options for compiler.
|
||||
*/
|
||||
export interface InternalOptions {
|
||||
/**
|
||||
* Whether to run all template checks and generate extended template diagnostics.
|
||||
*/
|
||||
_extendedTemplateDiagnostics?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A merged interface of all of the various Angular compiler options, as well as the standard
|
||||
* `ts.CompilerOptions`.
|
||||
@@ -45,4 +55,4 @@ export interface TestOnlyOptions {
|
||||
export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options,
|
||||
NgcCompatibilityOptions, StrictTemplateOptions,
|
||||
TestOnlyOptions, I18nOptions, TargetOptions,
|
||||
MiscOptions {}
|
||||
InternalOptions, MiscOptions {}
|
||||
|
||||
@@ -30,6 +30,8 @@ import {ivySwitchTransform} from '../../switch';
|
||||
import {aliasTransformFactory, CompilationMode, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform';
|
||||
import {TemplateTypeCheckerImpl} from '../../typecheck';
|
||||
import {OptimizeFor, TemplateTypeChecker, TypeCheckingConfig} from '../../typecheck/api';
|
||||
import {ExtendedTemplateCheckerImpl} from '../../typecheck/extended';
|
||||
import {InvalidBananaInBoxCheck} from '../../typecheck/extended/src/template_checks/invalid_banana_in_box';
|
||||
import {getSourceFileOrNull, isDtsPath, resolveModuleName, toUnredirectedSourceFile} from '../../util/src/typescript';
|
||||
import {Xi18nContext} from '../../xi18n';
|
||||
import {LazyRoute, NgCompilerAdapter, NgCompilerOptions} from '../api';
|
||||
@@ -316,6 +318,12 @@ export class NgCompiler {
|
||||
readonly usePoisonedData: boolean,
|
||||
private livePerfRecorder: ActivePerfRecorder,
|
||||
) {
|
||||
if (this.options._extendedTemplateDiagnostics === true &&
|
||||
this.options.strictTemplates === false) {
|
||||
throw new Error(
|
||||
'The \'_extendedTemplateDiagnostics\' option requires \'strictTemplates\' to also be enabled.');
|
||||
}
|
||||
|
||||
this.constructionDiagnostics.push(...this.adapter.constructionDiagnostics);
|
||||
const incompatibleTypeCheckOptionsDiagnostic = verifyCompatibleTypeCheckOptions(this.options);
|
||||
if (incompatibleTypeCheckOptionsDiagnostic !== null) {
|
||||
@@ -425,8 +433,12 @@ export class NgCompiler {
|
||||
* Get all Angular-related diagnostics for this compilation.
|
||||
*/
|
||||
getDiagnostics(): ts.Diagnostic[] {
|
||||
return this.addMessageTextDetails(
|
||||
[...this.getNonTemplateDiagnostics(), ...this.getTemplateDiagnostics()]);
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
diagnostics.push(...this.getNonTemplateDiagnostics(), ...this.getTemplateDiagnostics());
|
||||
if (this.options._extendedTemplateDiagnostics) {
|
||||
diagnostics.push(...this.getExtendedTemplateDiagnostics());
|
||||
}
|
||||
return this.addMessageTextDetails(diagnostics);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,10 +447,14 @@ export class NgCompiler {
|
||||
* If a `ts.SourceFile` is passed, only diagnostics related to that file are returned.
|
||||
*/
|
||||
getDiagnosticsForFile(file: ts.SourceFile, optimizeFor: OptimizeFor): ts.Diagnostic[] {
|
||||
return this.addMessageTextDetails([
|
||||
...this.getNonTemplateDiagnostics().filter(diag => diag.file === file),
|
||||
...this.getTemplateDiagnosticsForFile(file, optimizeFor)
|
||||
]);
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
diagnostics.push(
|
||||
...this.getNonTemplateDiagnostics().filter(diag => diag.file === file),
|
||||
...this.getTemplateDiagnosticsForFile(file, optimizeFor));
|
||||
if (this.options._extendedTemplateDiagnostics) {
|
||||
diagnostics.push(...this.getExtendedTemplateDiagnostics(file));
|
||||
}
|
||||
return this.addMessageTextDetails(diagnostics);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -892,6 +908,30 @@ export class NgCompiler {
|
||||
return this.nonTemplateDiagnostics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the `extendedTemplateCheck` phase of the trait compiler
|
||||
* @param sf optional parameter to get diagnostics for a certain file
|
||||
* or all files in the program if `sf` is undefined
|
||||
* @returns generated extended template diagnostics
|
||||
*/
|
||||
private getExtendedTemplateDiagnostics(sf?: ts.SourceFile): ts.Diagnostic[] {
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
const compilation = this.ensureAnalyzed();
|
||||
const typeChecker = this.inputProgram.getTypeChecker();
|
||||
const templateChecks = [new InvalidBananaInBoxCheck()];
|
||||
const extendedTemplateChecker = new ExtendedTemplateCheckerImpl(
|
||||
compilation.templateTypeChecker, typeChecker, templateChecks);
|
||||
if (sf !== undefined) {
|
||||
return compilation.traitCompiler.extendedTemplateCheck(sf, extendedTemplateChecker);
|
||||
}
|
||||
for (const sf of this.inputProgram.getSourceFiles()) {
|
||||
diagnostics.push(
|
||||
...compilation.traitCompiler.extendedTemplateCheck(sf, extendedTemplateChecker));
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
private makeCompilation(): LazyCompilationState {
|
||||
const checker = this.inputProgram.getTypeChecker();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/api",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck/extended/api",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"//packages/compiler-cli/src/ngtsc/xi18n",
|
||||
"@npm//typescript",
|
||||
|
||||
@@ -15,6 +15,7 @@ import {IndexingContext} from '../../indexer';
|
||||
import {ClassDeclaration, Decorator} from '../../reflection';
|
||||
import {ImportManager} from '../../translator';
|
||||
import {TypeCheckContext} from '../../typecheck/api';
|
||||
import {ExtendedTemplateChecker} from '../../typecheck/extended/api';
|
||||
import {Xi18nContext} from '../../xi18n';
|
||||
|
||||
/**
|
||||
@@ -187,6 +188,10 @@ export interface DecoratorHandler<D, A, S extends SemanticSymbol|null, R> {
|
||||
(ctx: TypeCheckContext, node: ClassDeclaration, analysis: Readonly<A>,
|
||||
resolution: Readonly<R>): void;
|
||||
|
||||
extendedTemplateCheck?
|
||||
(component: ts.ClassDeclaration, extendedTemplateChecker: ExtendedTemplateChecker):
|
||||
ts.Diagnostic[];
|
||||
|
||||
/**
|
||||
* Generate a description of the field which should be added to the class, including any
|
||||
* initialization code to be generated.
|
||||
|
||||
@@ -14,8 +14,9 @@ import {IncrementalBuild} from '../../incremental/api';
|
||||
import {SemanticDepGraphUpdater, SemanticSymbol} from '../../incremental/semantic_graph';
|
||||
import {IndexingContext} from '../../indexer';
|
||||
import {PerfEvent, PerfRecorder} from '../../perf';
|
||||
import {ClassDeclaration, DeclarationNode, Decorator, ReflectionHost} from '../../reflection';
|
||||
import {ClassDeclaration, DeclarationNode, Decorator, isNamedClassDeclaration, ReflectionHost} from '../../reflection';
|
||||
import {ProgramTypeCheckAdapter, TypeCheckContext} from '../../typecheck/api';
|
||||
import {ExtendedTemplateChecker} from '../../typecheck/extended/api';
|
||||
import {getSourceFile, isExported} from '../../util/src/typescript';
|
||||
import {Xi18nContext} from '../../xi18n';
|
||||
|
||||
@@ -490,6 +491,29 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
extendedTemplateCheck(sf: ts.SourceFile, extendedTemplateChecker: ExtendedTemplateChecker):
|
||||
ts.Diagnostic[] {
|
||||
const classes = this.fileToClasses.get(sf);
|
||||
if (classes === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const diagnostics: ts.Diagnostic[] = [];
|
||||
for (const clazz of classes) {
|
||||
if (!isNamedClassDeclaration(clazz)) {
|
||||
continue;
|
||||
}
|
||||
const record = this.classes.get(clazz)!;
|
||||
for (const trait of record.traits) {
|
||||
if (trait.handler.extendedTemplateCheck === undefined) {
|
||||
continue;
|
||||
}
|
||||
diagnostics.push(...trait.handler.extendedTemplateCheck(clazz, extendedTemplateChecker));
|
||||
}
|
||||
}
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
index(ctx: IndexingContext): void {
|
||||
for (const clazz of this.classes.keys()) {
|
||||
const record = this.classes.get(clazz)!;
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ load("//tools:defaults.bzl", "ts_library")
|
||||
ts_library(
|
||||
name = "invalid_banana_in_box",
|
||||
srcs = ["index.ts"],
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc/typecheck/extended:__subpackages__"],
|
||||
visibility = ["//packages/compiler-cli/src/ngtsc:__subpackages__"],
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
|
||||
Reference in New Issue
Block a user