-
Notifications
You must be signed in to change notification settings - Fork 234
/
directiveClassSuffixRule.ts
70 lines (59 loc) · 2.31 KB
/
directiveClassSuffixRule.ts
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
61
62
63
64
65
66
67
68
69
70
import { sprintf } from 'sprintf-js';
import * as Lint from 'tslint';
import * as ts from 'typescript';
import { DirectiveMetadata } from './angular/metadata';
import { NgWalker } from './angular/ngWalker';
import { getSymbolName } from './util/utils';
const ValidatorSuffix = 'Validator';
export class Rule extends Lint.Rules.AbstractRule {
static readonly metadata: Lint.IRuleMetadata = {
description: 'Classes decorated with @Directive must have suffix "Directive" (or custom) in their name.',
descriptionDetails: 'See more at https://angular.io/styleguide#style-02-03.',
optionExamples: [true, [true, 'Directive', 'MySuffix']],
options: {
items: {
type: 'string'
},
minLength: 0,
type: 'array'
},
optionsDescription: 'Supply a list of allowed component suffixes. Defaults to "Directive".',
rationale: 'Consistent conventions make it easy to quickly identify and reference assets of different types.',
ruleName: 'directive-class-suffix',
type: 'style',
typescriptOnly: true
};
static readonly FAILURE_STRING = 'The name of the class %s should end with the suffix %s (https://angular.io/styleguide#style-02-03)';
static validate(className: string, suffixes: string[]): boolean {
return suffixes.some(s => className.endsWith(s));
}
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const walker = new Walker(sourceFile, this.getOptions());
return this.applyWithWalker(walker);
}
}
class Walker extends NgWalker {
protected visitNgDirective(metadata: DirectiveMetadata) {
const name = metadata.controller.name!;
const className = name.text;
const options = this.getOptions();
const suffixes: string[] = options.length ? options : ['Directive'];
const { heritageClauses } = metadata.controller;
if (heritageClauses) {
const i = heritageClauses.filter(h => h.token === ts.SyntaxKind.ImplementsKeyword);
if (
i.length !== 0 &&
i[0].types
.map(getSymbolName)
.filter(Boolean)
.some(x => x.endsWith(ValidatorSuffix))
) {
suffixes.push(ValidatorSuffix);
}
}
if (!Rule.validate(className, suffixes)) {
this.addFailureAtNode(name, sprintf(Rule.FAILURE_STRING, className, suffixes.join(', ')));
}
super.visitNgDirective(metadata);
}
}