A comprehensive static code analysis tool for Angular TypeScript projects that implements TSLint rules enforcing Angular's official style guide.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Angular template validation rules that cover accessibility, performance, correctness, and best practices for Angular component templates.
Prevents common two-way binding syntax mistakes (banana in a box pattern).
/**
* Ensures correct two-way binding syntax [()] instead of ([])
* Prevents common template binding mistakes
*/
export class TemplateBananaInBoxRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
TSLint configuration:
{
"rules": {
"template-banana-in-box": true
}
}Correct two-way binding:
<input [(ngModel)]="value">Incorrect (banana in box):
<input ([ngModel])="value"> <!-- Wrong: parentheses inside brackets -->Prevents function calls in Angular templates for performance reasons.
/**
* Prevents function calls in templates that execute on every change detection
* Improves application performance by avoiding unnecessary computations
*/
export class TemplateNoCallExpressionRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
Bad (function calls in template):
<div>{{ getFullName() }}</div>
<button (click)="calculate().then(handleResult)">Calculate</button>Good (use properties or pipes):
<div>{{ fullName }}</div>
<div>{{ userData | fullName }}</div>
<button (click)="handleCalculate()">Calculate</button>Prevents use of 'any' type in Angular templates.
/**
* Prevents use of '$any()' type assertion in templates
* Maintains type safety in Angular templates
*/
export class TemplateNoAnyRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Prevents negation of async pipe results which can cause issues.
/**
* Prevents negating async pipe results in templates
* Avoids potential issues with truthy/falsy evaluation of observables
*/
export class TemplateNoNegatedAsyncRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
Bad:
<div *ngIf="!(data$ | async)">No data</div>Good:
<div *ngIf="(data$ | async) === null">No data</div>
<div *ngIf="(data$ | async)?.length === 0">No data</div>Enforces use of trackBy functions with *ngFor for performance.
/**
* Enforces trackBy functions with *ngFor directives
* Improves performance by helping Angular track list changes efficiently
*/
export class TemplateUseTrackByFunctionRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
Good with trackBy:
<div *ngFor="let item of items; trackBy: trackByFn">{{ item.name }}</div>Component:
trackByFn(index: number, item: any) {
return item.id;
}Measures and limits conditional complexity in templates.
/**
* Enforces maximum conditional complexity in Angular templates
* Promotes readable templates by limiting nested conditionals
*/
export class TemplateConditionalComplexityRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Measures cyclomatic complexity in Angular templates.
/**
* Measures cyclomatic complexity in Angular templates
* Helps identify overly complex templates that should be refactored
*/
export class TemplateCyclomaticComplexityRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Enforces internationalization attributes for text content.
/**
* Enforces i18n attributes on elements with text content
* Ensures application text is properly marked for internationalization
*/
export class TemplateI18nRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
Good with i18n:
<p i18n="@@welcome.message">Welcome to our application</p>
<button i18n="@@button.save">Save</button>Prevents use of autofocus attribute for accessibility reasons.
/**
* Prevents autofocus attribute usage in templates
* Improves accessibility by avoiding unexpected focus changes
*/
export class TemplateNoAutofocusRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Prevents use of distracting HTML elements like <blink> and <marquee>.
/**
* Prevents use of distracting HTML elements
* Improves accessibility and user experience
*/
export class TemplateNoDistractingElementsRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Ensures click events have corresponding keyboard events for accessibility.
/**
* Ensures click events have corresponding keyboard event handlers
* Improves accessibility by providing keyboard navigation alternatives
*/
export class TemplateClickEventsHaveKeyEventsRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}Usage Examples:
Good with keyboard events:
<div (click)="handleClick()" (keyup.enter)="handleClick()" (keyup.space)="handleClick()">
Clickable content
</div>Ensures mouse events have corresponding keyboard alternatives.
/**
* Ensures mouse events have corresponding keyboard event alternatives
* Maintains accessibility for keyboard-only users
*/
export class TemplateMouseEventsHaveKeyEventsRule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata;
static readonly FAILURE_STRING: string;
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[];
}{
"rules": {
"template-banana-in-box": true,
"template-no-call-expression": true,
"template-no-any": true,
"template-no-negated-async": true,
"template-use-track-by-function": true,
"template-conditional-complexity": [true, 4],
"template-cyclomatic-complexity": [true, 5],
"template-i18n": [true, "check-id", "check-text"],
"template-no-autofocus": true,
"template-no-distracting-elements": true,
"template-click-events-have-key-events": true,
"template-mouse-events-have-key-events": true
}
}Template rules help identify performance bottlenecks:
Many template rules enforce accessibility best practices:
Install with Tessl CLI
npx tessl i tessl/npm-codelyzer