/
noAttributeDecoratorRule.ts
64 lines (50 loc) · 1.98 KB
/
noAttributeDecoratorRule.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
import { IRuleMetadata, RuleFailure, WalkContext } from 'tslint';
import { AbstractRule } from 'tslint/lib/rules';
import {
ConstructorDeclaration,
createNodeArray,
Decorator,
forEachChild,
isConstructorDeclaration,
Node,
ParameterDeclaration,
SourceFile
} from 'typescript';
import { getDecoratorName } from './util/utils';
const ATTRIBUTE = 'Attribute';
export class Rule extends AbstractRule {
static readonly metadata: IRuleMetadata = {
description: `Disallows usage of @${ATTRIBUTE} decorator.`,
options: null,
optionsDescription: 'Not configurable.',
ruleName: 'no-attribute-decorator',
type: 'functionality',
typescriptOnly: true
};
static readonly FAILURE_STRING = `@${ATTRIBUTE} is considered bad practice. Use @Input instead.`;
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
const callbackHandler = (walkContext: WalkContext<void>, node: Node): void => {
if (isConstructorDeclaration(node)) validateConstructor(walkContext, node);
};
const isAttributeDecorator = (decorator: Decorator): boolean => getDecoratorName(decorator) === ATTRIBUTE;
const validateConstructor = (walkContext: WalkContext<void>, node: ConstructorDeclaration): void => {
node.parameters.forEach(parameter => validateParameter(walkContext, parameter));
};
const validateDecorator = (walkContext: WalkContext<void>, decorator: Decorator): void => {
if (!isAttributeDecorator(decorator)) return;
walkContext.addFailureAtNode(decorator, Rule.FAILURE_STRING);
};
const validateParameter = (walkContext: WalkContext<void>, node: ParameterDeclaration): void => {
createNodeArray(node.decorators).forEach(decorator => validateDecorator(walkContext, decorator));
};
const walk = (walkContext: WalkContext<void>): void => {
const { sourceFile } = walkContext;
const callback = (node: Node): void => {
callbackHandler(walkContext, node);
forEachChild(node, callback);
};
forEachChild(sourceFile, callback);
};