mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(compiler-cli): add abstract TemplateCheckWithVisitor class (#43232)
Add an abstract class that has a default implementation of the run function and visits all nodes. Authors of template checks can extend this class and override the `visitNode` method to return diagnostics. Refs #42966 PR Close #43232
This commit is contained in:
committed by
Jessica Janiuk
parent
dee04bd96e
commit
46e68df2cd
@@ -6,7 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {TmplAstNode} from '@angular/compiler';
|
||||
import {AST, RecursiveAstVisitor, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstContent, TmplAstElement, TmplAstIcu, TmplAstNode, TmplAstRecursiveVisitor, TmplAstReference, TmplAstTemplate, TmplAstText, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler';
|
||||
import {ASTWithSource} from '@angular/compiler/src/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode} from '../../../diagnostics';
|
||||
@@ -38,3 +39,103 @@ export interface TemplateContext {
|
||||
*/
|
||||
typeChecker: ts.TypeChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
* This abstract class provides a base implementation for the run method.
|
||||
*/
|
||||
export abstract class TemplateCheckWithVisitor<T extends ErrorCode> implements TemplateCheck<T> {
|
||||
abstract code: T;
|
||||
|
||||
/**
|
||||
* Base implementation for run function, visits all nodes in template and calls
|
||||
* `visitNode()` for each one.
|
||||
*/
|
||||
run(ctx: TemplateContext, component: ts.ClassDeclaration,
|
||||
template: TmplAstNode[]): NgTemplateDiagnostic<T>[] {
|
||||
const visitor = new TemplateVisitor<T>(ctx, component, this);
|
||||
return visitor.getDiagnostics(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit a TmplAstNode or AST node of the template. Authors should override this
|
||||
* method to implement the check and return diagnostics.
|
||||
*/
|
||||
abstract visitNode(ctx: TemplateContext, component: ts.ClassDeclaration, node: TmplAstNode|AST):
|
||||
NgTemplateDiagnostic<T>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits all nodes in a template (TmplAstNode and AST) and calls `visitNode` for each one.
|
||||
*/
|
||||
class TemplateVisitor<T extends ErrorCode> extends RecursiveAstVisitor implements
|
||||
TmplAstRecursiveVisitor {
|
||||
diagnostics: NgTemplateDiagnostic<T>[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly ctx: TemplateContext, private readonly component: ts.ClassDeclaration,
|
||||
private readonly check: TemplateCheckWithVisitor<T>) {
|
||||
super();
|
||||
}
|
||||
|
||||
override visit(node: AST|TmplAstNode, context?: any) {
|
||||
this.diagnostics.push(...this.check.visitNode(this.ctx, this.component, node));
|
||||
node.visit(this);
|
||||
}
|
||||
|
||||
visitAllNodes(nodes: TmplAstNode[]) {
|
||||
for (const node of nodes) {
|
||||
this.visit(node);
|
||||
}
|
||||
}
|
||||
|
||||
visitAst(ast: AST) {
|
||||
if (ast instanceof ASTWithSource) {
|
||||
ast = ast.ast;
|
||||
}
|
||||
this.visit(ast);
|
||||
}
|
||||
|
||||
visitElement(element: TmplAstElement) {
|
||||
this.visitAllNodes(element.attributes);
|
||||
this.visitAllNodes(element.inputs);
|
||||
this.visitAllNodes(element.outputs);
|
||||
this.visitAllNodes(element.references);
|
||||
this.visitAllNodes(element.children);
|
||||
}
|
||||
|
||||
visitTemplate(template: TmplAstTemplate) {
|
||||
this.visitAllNodes(template.attributes);
|
||||
if (template.tagName === 'ng-template') {
|
||||
// Only visit input/outputs/templateAttrs if this isn't an inline template node
|
||||
// generated for a structural directive (like `<div *ngIf></div>`). These nodes
|
||||
// would be visited when the underlying element of an inline template node is processed.
|
||||
this.visitAllNodes(template.inputs);
|
||||
this.visitAllNodes(template.outputs);
|
||||
this.visitAllNodes(template.templateAttrs);
|
||||
}
|
||||
this.visitAllNodes(template.variables);
|
||||
this.visitAllNodes(template.references);
|
||||
this.visitAllNodes(template.children);
|
||||
}
|
||||
visitContent(content: TmplAstContent): void {}
|
||||
visitVariable(variable: TmplAstVariable): void {}
|
||||
visitReference(reference: TmplAstReference): void {}
|
||||
visitTextAttribute(attribute: TmplAstTextAttribute): void {}
|
||||
visitBoundAttribute(attribute: TmplAstBoundAttribute): void {
|
||||
this.visitAst(attribute.value);
|
||||
}
|
||||
visitBoundEvent(attribute: TmplAstBoundEvent): void {
|
||||
this.visitAst(attribute.handler);
|
||||
}
|
||||
visitText(text: TmplAstText): void {}
|
||||
visitBoundText(text: TmplAstBoundText): void {
|
||||
this.visitAst(text.value);
|
||||
}
|
||||
visitIcu(icu: TmplAstIcu): void {}
|
||||
|
||||
getDiagnostics(template: TmplAstNode[]): NgTemplateDiagnostic<T>[] {
|
||||
this.diagnostics = [];
|
||||
this.visitAllNodes(template);
|
||||
return this.diagnostics;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user