forked from mgechev/codelyzer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
noOutputRenameRule.ts
55 lines (44 loc) · 2.09 KB
/
noOutputRenameRule.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
import { IRuleMetadata, RuleFailure, Rules } from 'tslint/lib';
import { Decorator, PropertyDeclaration, SourceFile } from 'typescript/lib/typescript';
import { DirectiveMetadata } from './angular/metadata';
import { NgWalker } from './angular/ngWalker';
export class Rule extends Rules.AbstractRule {
static readonly metadata: IRuleMetadata = {
description: 'Disallows renaming directive outputs by providing a string to the decorator.',
descriptionDetails: 'See more at https://angular.io/styleguide#style-05-13.',
options: null,
optionsDescription: 'Not configurable.',
rationale: 'Two names for the same property (one private, one public) is inherently confusing.',
ruleName: 'no-output-rename',
type: 'maintainability',
typescriptOnly: true
};
static readonly FAILURE_STRING = '@Outputs should not be renamed';
apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithWalker(new OutputMetadataWalker(sourceFile, this.getOptions()));
}
}
export const getFailureMessage = (): string => {
return Rule.FAILURE_STRING;
};
export class OutputMetadataWalker extends NgWalker {
private directiveSelectors!: ReadonlySet<DirectiveMetadata['selector']>;
protected visitNgDirective(metadata: DirectiveMetadata): void {
this.directiveSelectors = new Set((metadata.selector || '').replace(/[\[\]\s]/g, '').split(','));
super.visitNgDirective(metadata);
}
protected visitNgOutput(property: PropertyDeclaration, output: Decorator, args: string[]) {
this.validateOutput(property, output, args);
super.visitNgOutput(property, output, args);
}
private canPropertyBeAliased(propertyAlias: string, propertyName: string): boolean {
return !!(this.directiveSelectors && this.directiveSelectors.has(propertyAlias) && propertyAlias !== propertyName);
}
private validateOutput(property: PropertyDeclaration, output: Decorator, args: string[]) {
const propertyName = property.name.getText();
if (args.length === 0 || this.canPropertyBeAliased(args[0], propertyName)) {
return;
}
this.addFailureAtNode(property, getFailureMessage());
}
}