forked from mgechev/codelyzer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtemplateNoCallExpressionRule.ts
More file actions
60 lines (48 loc) · 2.05 KB
/
templateNoCallExpressionRule.ts
File metadata and controls
60 lines (48 loc) · 2.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { MethodCall } from '@angular/compiler';
import { IRuleMetadata, RuleFailure } from 'tslint';
import { AbstractRule } from 'tslint/lib/rules';
import { SourceFile } from 'typescript';
import { NgWalker, NgWalkerConfig } from './angular/ngWalker';
import { BasicTemplateAstVisitor } from './angular/templates/basicTemplateAstVisitor';
import { RecursiveAngularExpressionVisitor } from './angular/templates/recursiveAngularExpressionVisitor';
const ALLOWED_METHOD_NAMES: ReadonlySet<string> = new Set(['$any']);
export class Rule extends AbstractRule {
static readonly metadata: IRuleMetadata = {
description: 'Disallows calling expressions in templates, except for output handlers.',
options: null,
optionsDescription: 'Not configurable.',
rationale: 'Calling expressions in templates causes it to run on every change detection cycle and may cause performance issues.',
ruleName: 'template-no-call-expression',
type: 'maintainability',
typescriptOnly: true,
};
static readonly FAILURE_STRING = 'Avoid calling expressions in templates';
apply(sourceFile: SourceFile): RuleFailure[] {
const walkerConfig: NgWalkerConfig = {
expressionVisitorCtrl: ExpressionVisitorCtrl,
templateVisitorCtrl: TemplateVisitorCtrl,
};
const walker = new NgWalker(sourceFile, this.getOptions(), walkerConfig);
return this.applyWithWalker(walker);
}
}
class TemplateVisitorCtrl extends BasicTemplateAstVisitor {
visitEvent(): any {}
}
class ExpressionVisitorCtrl extends RecursiveAngularExpressionVisitor {
visitMethodCall(ast: MethodCall, context: any): any {
this.validateMethodCall(ast);
super.visitMethodCall(ast, context);
}
private generateFailure(ast: MethodCall): void {
const {
span: { end: endSpan, start: startSpan },
} = ast;
this.addFailureFromStartToEnd(startSpan, endSpan, Rule.FAILURE_STRING);
}
private validateMethodCall(ast: MethodCall): void {
const isMethodAllowed = ALLOWED_METHOD_NAMES.has(ast.name);
if (isMethodAllowed) return;
this.generateFailure(ast);
}
}