Skip to content

Commit 0aa16de

Browse files
committed
Merge branch 'master' of github.com:mgechev/ng2lint
* 'master' of github.com:mgechev/ng2lint: fix attribute rule update alignment and attribute rule update rules to use tslint structure and ng2walker update README for forwardRef rule and added some types to functions refactor rules and walker to use single rulesBase update input output tests add fowardRefRule + walker + test
2 parents f75cd0c + 6e227f2 commit 0aa16de

12 files changed

+199
-179
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Below you can find a recommended configuration which is based on the [Angular 2
1919
"output-parameter-decorator": true,
2020
"attribute-parameter-decorator": true,
2121
"input-property-directive": true,
22-
"output-property-directive": true
22+
"output-property-directive": true,
23+
"call-forward-ref":true
2324
}
2425
```
2526

@@ -39,7 +40,7 @@ Below you can find a recommended configuration which is based on the [Angular 2
3940
- [x] Do not rename outputs.
4041
- [ ] Externalize template above *n* lines of code.
4142
- [x] Do not use the `@Attribute` decorator.
42-
- [ ] Do not use `forwardRef`.
43+
- [x] Do not use `forwardRef`.
4344
- [ ] Rise a warning for impure pipes.
4445
- [ ] Do not declare global providers.
4546
- [ ] Follow convention for naming the routes.
+38-10
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,47 @@
11
import * as Lint from 'tslint/lib/lint';
22
import * as ts from 'typescript';
3-
import {ConstructorRule} from "./parameterConstructorBase";
4-
import {decoratorValidator} from "./util/decoratorValidator";
3+
import {sprintf} from 'sprintf-js';
54

6-
const FAILURE_STRING = 'In the constructor of class "%s", the parameter "%s" uses the @Attribute decorator, ' +
7-
'which is considered as a bad practice. Please, consider construction of type "@Input() %s: string"';
5+
export class Rule extends Lint.Rules.AbstractRule {
86

9-
const attributeCondition = (name)=>{
10-
return (name=='Attribute')
11-
};
7+
public apply(sourceFile:ts.SourceFile):Lint.RuleFailure[] {
8+
return this.applyWithWalker(
9+
new ConstructorMetadataWalker(sourceFile,
10+
this.getOptions()));
11+
}
12+
13+
static FAILURE_STRING:string = 'In the constructor of class "%s",' +
14+
' the parameter "%s" uses the @Attribute decorator, ' +
15+
'which is considered as a bad practice. Please,' +
16+
' consider construction of type "@Input() %s: string"';
1217

13-
export class Rule extends ConstructorRule {
18+
}
1419

15-
constructor(ruleName:string, value:any, disabledIntervals:Lint.IDisabledInterval[]) {
16-
super(ruleName, value, disabledIntervals,decoratorValidator(attributeCondition),FAILURE_STRING);
20+
export class ConstructorMetadataWalker extends Lint.RuleWalker {
21+
22+
visitConstructorDeclaration(node:ts.ConstructorDeclaration) {
23+
let parentName = (<ts.ClassDeclaration>node.parent).name.text;
24+
(node.parameters || []).forEach(this.validateParameter.bind(this, parentName));
25+
super.visitConstructorDeclaration(node);
1726
}
1827

28+
validateParameter(className:string, parameter) {
29+
let parameterName = (<ts.Identifier>parameter.name).text;
30+
if (parameter.decorators) {
31+
parameter.decorators.forEach((decorator)=> {
32+
let baseExpr = <any>decorator.expression || {};
33+
let expr = baseExpr.expression || {};
34+
let name = expr.text;
35+
if (name == 'Attribute') {
36+
let failureConfig:string[] = [className, parameterName, parameterName];
37+
failureConfig.unshift(Rule.FAILURE_STRING);
38+
this.addFailure(
39+
this.createFailure(
40+
parameter.getStart(),
41+
parameter.getWidth(),
42+
sprintf.apply(this, failureConfig)));
43+
}
44+
})
45+
}
46+
}
1947
}

src/callForwardRefRule.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as Lint from 'tslint/lib/lint';
2+
import * as ts from 'typescript';
3+
import {sprintf} from 'sprintf-js';
4+
5+
export class Rule extends Lint.Rules.AbstractRule {
6+
7+
public apply(sourceFile:ts.SourceFile):Lint.RuleFailure[] {
8+
return this.applyWithWalker(
9+
new ExpressionCallMetadataWalker(sourceFile,
10+
this.getOptions()));
11+
}
12+
13+
static FAILURE_STRING:string = 'In the class "%s" you are calling forwardRef,' +
14+
' which is considered a bad practice ' +
15+
'and indicates either a cyclic dependency or ' +
16+
'inconsistency in the services declaration';
17+
}
18+
19+
20+
export class ExpressionCallMetadataWalker extends Lint.RuleWalker {
21+
22+
visitCallExpression(node:ts.CallExpression) {
23+
this.validateCallExpression(node);
24+
super.visitCallExpression(node);
25+
}
26+
27+
private validateCallExpression(callExpression) {
28+
if (callExpression.expression.text === 'forwardRef') {
29+
let currentNode:any = callExpression;
30+
while (currentNode.parent.parent) {
31+
currentNode = currentNode.parent;
32+
}
33+
let failureConfig:string[] = [currentNode.name.text];
34+
failureConfig.unshift(Rule.FAILURE_STRING);
35+
this.addFailure(
36+
this.createFailure(
37+
callExpression.getStart(),
38+
callExpression.getWidth(),
39+
sprintf.apply(this, failureConfig)));
40+
}
41+
}
42+
43+
}

src/inputPropertyDirectiveRule.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
import * as Lint from 'tslint/lib/lint';
22
import * as ts from 'typescript';
3-
import {ClassParameterRule} from "./propertyClassBase";
4-
import {decoratorValidator} from './util/decoratorValidator';
3+
import {sprintf} from 'sprintf-js';
4+
import {Ng2Walker} from "./util/ng2Walker";
55

6-
const FAILURE_STRING = 'In the class "%s", the directive input property "%s" should not be renamed.' +
7-
'Please, consider the following use "@Input() %s: string"';
6+
export class Rule extends Lint.Rules.AbstractRule {
87

9-
const renameInputCondition = (name, arg, element)=> {
10-
let memberName = element.name.text;
11-
return (name === 'Input' && arg && memberName != arg.text);
12-
};
8+
public apply(sourceFile:ts.SourceFile):Lint.RuleFailure[] {
9+
return this.applyWithWalker(
10+
new InputMetadataWalker(sourceFile,
11+
this.getOptions()));
12+
}
1313

14-
export class Rule extends ClassParameterRule {
14+
static FAILURE_STRING:string = 'In the class "%s", the directive ' +
15+
'input property "%s" should not be renamed.' +
16+
'Please, consider the following use "@Input() %s: string"';
17+
}
1518

16-
constructor(ruleName:string, value:any, disabledIntervals:Lint.IDisabledInterval[]) {
17-
super(ruleName, value, disabledIntervals, decoratorValidator(renameInputCondition), FAILURE_STRING);
18-
}
1919

20+
export class InputMetadataWalker extends Ng2Walker {
21+
22+
visitNg2Input(property:ts.PropertyDeclaration, input:ts.Decorator, args:string[]) {
23+
let className = (<any>property).parent.name.text;
24+
let memberName = (<any>property.name).text;
25+
if (args.length != 0 && memberName != args[0]) {
26+
let failureConfig:string[] = [className, memberName, memberName];
27+
failureConfig.unshift(Rule.FAILURE_STRING);
28+
this.addFailure(
29+
this.createFailure(
30+
property.getStart(),
31+
property.getWidth(),
32+
sprintf.apply(this, failureConfig)));
33+
}
34+
}
2035
}

src/outputPropertyDirectiveRule.ts

+27-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
import * as Lint from 'tslint/lib/lint';
22
import * as ts from 'typescript';
3-
import {ClassParameterRule} from "./propertyClassBase";
4-
import {decoratorValidator} from './util/decoratorValidator';
3+
import {sprintf} from 'sprintf-js';
4+
import {Ng2Walker} from "./util/ng2Walker";
55

6-
const FAILURE_STRING = 'In the class "%s", the directive output property "%s" should not be renamed.' +
7-
'Please, consider the following use "@Output() %s = new EventEmitter();"';
6+
export class Rule extends Lint.Rules.AbstractRule {
87

9-
const renameOutputCondition = (name, arg, element)=> {
10-
let memberName = element.name.text;
11-
return (name === 'Output' && arg && memberName !== arg.text);
12-
};
8+
public apply(sourceFile:ts.SourceFile):Lint.RuleFailure[] {
9+
return this.applyWithWalker(
10+
new OutputMetadataWalker(sourceFile,
11+
this.getOptions()));
12+
}
1313

14-
export class Rule extends ClassParameterRule {
14+
static FAILURE_STRING:string = 'In the class "%s", the directive output ' +
15+
'property "%s" should not be renamed.' +
16+
'Please, consider the following use "@Output() %s = new EventEmitter();"';
17+
}
1518

16-
constructor(ruleName:string, value:any, disabledIntervals:Lint.IDisabledInterval[]) {
17-
super(ruleName, value, disabledIntervals, decoratorValidator(renameOutputCondition), FAILURE_STRING);
18-
}
1919

20+
export class OutputMetadataWalker extends Ng2Walker {
21+
22+
visitNg2Output(property:ts.PropertyDeclaration, output:ts.Decorator, args:string[]) {
23+
let className = (<any>property).parent.name.text;
24+
let memberName = (<any>property.name).text;
25+
if (args.length != 0 && memberName != args[0]) {
26+
let failureConfig:string[] = [className, memberName, memberName];
27+
failureConfig.unshift(Rule.FAILURE_STRING);
28+
this.addFailure(
29+
this.createFailure(
30+
property.getStart(),
31+
property.getWidth(),
32+
sprintf.apply(this, failureConfig)));
33+
}
34+
}
2035
}

src/parameterConstructorBase.ts

-60
This file was deleted.

src/propertyClassBase.ts

-58
This file was deleted.

src/util/decoratorValidator.ts

-18
This file was deleted.

test/attributeParameterDecoratorRule.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ describe('attribute-parameter-decorator', () => {
66
let source = `
77
class ButtonComponent {
88
label: string;
9-
constructor(public @Attribute('label') label) {
9+
constructor(@Attribute('label') label) {
1010
this.label = label;
1111
}
1212
}`;
@@ -15,11 +15,11 @@ describe('attribute-parameter-decorator', () => {
1515
'which is considered as a bad practice. Please, consider construction of type "@Input() label: string"',
1616
startPosition: {
1717
line: 3,
18-
character: 35
18+
character: 28
1919
},
2020
endPosition: {
2121
line: 3,
22-
character: 60
22+
character: 53
2323
}
2424
});
2525
});

0 commit comments

Comments
 (0)