Skip to content

Commit 465c653

Browse files
author
PreskoIsTheGreatest
committed
add pipe transform interfaces rule; fix forgoten call to super method in life cycle hooks and updated README
1 parent d074771 commit 465c653

File tree

4 files changed

+97
-2
lines changed

4 files changed

+97
-2
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ Below you can find a recommended configuration which is based on the [Angular 2
2121
"input-property-directive": true,
2222
"output-property-directive": true,
2323
"call-forward-ref":true,
24-
"life-cycle-hook":true
24+
"life-cycle-hook":true,
25+
"pipe-transform-interface":true
2526
}
2627
```
2728

@@ -56,7 +57,7 @@ Below you can find a recommended configuration which is based on the [Angular 2
5657
- [ ] Rise warning on complex logic inside of the templates.
5758
- [ ] Do not manipulate elements referenced within the template.
5859
- [x] Implement life-cycle hooks explicitly.
59-
- [ ] Implement Pipe transform interface for pipes.
60+
- [x] Implement Pipe transform interface for pipes.
6061
- [ ] Proper naming for pipes (kebab-case, optionally prefixed).
6162

6263
## License

src/lifeCycleHookRule.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export class ClassMetadataWalker extends Lint.RuleWalker {
5555
node.getWidth(),
5656
sprintf.apply(this, this.formatFailure(className, missing))));
5757
}
58+
super.visitClassDeclaration(node);
5859
}
5960

6061

src/pipeTransformInterfaceRule.ts

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as Lint from 'tslint/lib/lint';
2+
import * as ts from 'typescript';
3+
import {sprintf} from 'sprintf-js';
4+
import SyntaxKind = require('./util/syntaxKind');
5+
6+
export class Rule extends Lint.Rules.AbstractRule {
7+
8+
public apply(sourceFile:ts.SourceFile):Lint.RuleFailure[] {
9+
return this.applyWithWalker(
10+
new ClassMetadataWalker(sourceFile,
11+
this.getOptions()));
12+
}
13+
14+
static FAILURE:string = 'The %s class has the Pipe decorator, so it should implement the PipeTransform interface';
15+
16+
static PIPE_INTERFACE_NAME = 'PipeTransform';
17+
}
18+
19+
export class ClassMetadataWalker extends Lint.RuleWalker {
20+
21+
visitClassDeclaration(node:ts.ClassDeclaration) {
22+
let decorators = node.decorators;
23+
if (decorators) {
24+
let pipes:Array<string> = decorators.map(d=>(<any>d.expression).expression.text).filter(t=>t === 'Pipe');
25+
if (pipes.length !== 0) {
26+
let className:string = node.name.text;
27+
if (!this.hasIPipeTransform(node)) {
28+
this.addFailure(
29+
this.createFailure(
30+
node.getStart(),
31+
node.getWidth(),
32+
sprintf.apply(this, [Rule.FAILURE, className])));
33+
}
34+
}
35+
}
36+
super.visitClassDeclaration(node);
37+
}
38+
39+
private hasIPipeTransform(node:ts.ClassDeclaration):boolean {
40+
let interfaces = [];
41+
if (node.heritageClauses) {
42+
let interfacesClause = node.heritageClauses
43+
.filter(h=>h.token === SyntaxKind.current().ImplementsKeyword);
44+
if (interfacesClause.length !== 0) {
45+
interfaces = interfacesClause[0].types
46+
.map(t=>(<any>t.expression).text);
47+
}
48+
}
49+
return interfaces.indexOf(Rule.PIPE_INTERFACE_NAME) !== -1;
50+
}
51+
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {assertFailure, assertSuccess} from './testHelper';
2+
3+
describe('pipe-transform-interface', () => {
4+
describe('invalid declaration of pipe', () => {
5+
it(`should fail, when a Pipe is declared without implementing the PipeTransform interface`, () => {
6+
let source = `
7+
@Pipe({name: 'fetch'})
8+
export class NewPipe{
9+
transform(url:string):any {
10+
}
11+
}`;
12+
assertFailure('pipe-transform-interface', source, {
13+
message: 'The NewPipe class has the Pipe decorator, so it should implement the PipeTransform interface',
14+
startPosition: {
15+
line: 1,
16+
character: 24
17+
},
18+
endPosition: {
19+
line: 5,
20+
character: 25
21+
}
22+
});
23+
});
24+
});
25+
describe('valid use of Pipe with the implementation of the PipeTransform interface', () => {
26+
it(`should succeed when Pipe is declared properly`, () => {
27+
let source = `
28+
@Pipe({name: 'fetch'})
29+
export class NewPipe implements PipeTransform{
30+
transform(url:string):any {
31+
}
32+
}`;
33+
assertSuccess('pipe-transform-interface', source);
34+
});
35+
});
36+
describe('valid use of empty class', () => {
37+
it(`should succeed, when Pipe is not used`, () => {
38+
let source = `class App{}`;
39+
assertSuccess('pipe-transform-interface', source);
40+
});
41+
});
42+
});

0 commit comments

Comments
 (0)