From 15da839e5d40ca856e7990b98b5e6e87f426bb3c Mon Sep 17 00:00:00 2001 From: mgechev Date: Wed, 21 Sep 2016 13:24:17 -0700 Subject: [PATCH] fix(InterfaceImplement): handle nested namespaces --- src/useLifeCycleInterfaceRule.ts | 18 +++++++++--------- src/usePipeTransformInterfaceRule.ts | 9 ++++++++- test/useLifeCycleInterfaceRule.spec.ts | 20 ++++++++++++++++++++ test/usePipeTransformInterfaceRule.spec.ts | 10 ++++++++++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/useLifeCycleInterfaceRule.ts b/src/useLifeCycleInterfaceRule.ts index 0ff1893b1..5c8bc8b80 100644 --- a/src/useLifeCycleInterfaceRule.ts +++ b/src/useLifeCycleInterfaceRule.ts @@ -3,6 +3,13 @@ import * as ts from 'typescript'; import {sprintf} from 'sprintf-js'; import SyntaxKind = require('./util/syntaxKind'); +const getInterfaceName = (t: any) => { + if (t.expression && t.expression.name) { + return t.expression.name.text; + } + return t.expression.text; +}; + export class Rule extends Lint.Rules.AbstractRule { static FAILURE:string = 'Implement lifecycle hook interface %s for method %s in class %s ($$09-01$$)'; @@ -43,14 +50,7 @@ export class ClassMetadataWalker extends Lint.RuleWalker { if (node.heritageClauses) { let interfacesClause = node.heritageClauses.filter(h=>h.token === syntaxKind.ImplementsKeyword); if (interfacesClause.length !== 0) { - interfaces = interfacesClause[0].types.map(t=>{ - let expr =(t.expression); - if(expr.expression && expr.expression.text == Rule.HOOKS_PREFIX){ - return expr.name.text; - } else { - return expr.text; - } - }); + interfaces = interfacesClause[0].types.map(getInterfaceName); } } return interfaces; @@ -78,5 +78,5 @@ export class ClassMetadataWalker extends Lint.RuleWalker { let isNotIn:boolean = interfaces.indexOf(hookName) === -1; return isNg && isHook && isNotIn; } - + } diff --git a/src/usePipeTransformInterfaceRule.ts b/src/usePipeTransformInterfaceRule.ts index a2d08df66..282a73e48 100644 --- a/src/usePipeTransformInterfaceRule.ts +++ b/src/usePipeTransformInterfaceRule.ts @@ -3,6 +3,13 @@ import * as ts from 'typescript'; import {sprintf} from 'sprintf-js'; import SyntaxKind = require('./util/syntaxKind'); +const getInterfaceName = (t: any) => { + if (t.expression && t.expression.name) { + return t.expression.name.text; + } + return t.expression.text; +}; + export class Rule extends Lint.Rules.AbstractRule { static FAILURE: string = 'The %s class has the Pipe decorator, so it should implement the PipeTransform interface'; static PIPE_INTERFACE_NAME = 'PipeTransform'; @@ -41,7 +48,7 @@ export class ClassMetadataWalker extends Lint.RuleWalker { let interfacesClause = node.heritageClauses .filter(h=>h.token === SyntaxKind.current().ImplementsKeyword); if (interfacesClause.length !== 0) { - interfaces = interfacesClause[0].types.map(t=>(t.expression).text); + interfaces = interfacesClause[0].types.map(getInterfaceName); } } return interfaces.indexOf(Rule.PIPE_INTERFACE_NAME) !== -1; diff --git a/test/useLifeCycleInterfaceRule.spec.ts b/test/useLifeCycleInterfaceRule.spec.ts index be455639a..cdb21043e 100644 --- a/test/useLifeCycleInterfaceRule.spec.ts +++ b/test/useLifeCycleInterfaceRule.spec.ts @@ -120,6 +120,7 @@ describe('use-life-cycle-interface', () => { assertSuccess('use-life-cycle-interface', source); }); }); + describe('valid declaration of life hooks, using ng.hookName', () => { it(`should succeed, when life cycle hook is used with it's interface`, () => { @@ -130,6 +131,25 @@ describe('use-life-cycle-interface', () => { }`; assertSuccess('use-life-cycle-interface', source); }); + + it('should succeed when life cycle hook is implemented by using any prefix', () => { + let source = ` + class App implements bar.OnInit { + ngOnInit(){ + } + }`; + assertSuccess('use-life-cycle-interface', source); + }); + + it('should succeed when life cycle hook is implemented by using nested interfaces', () => { + let source = ` + class App implements bar.foo.baz.OnInit { + ngOnInit(){ + } + }`; + assertSuccess('use-life-cycle-interface', source); + }); + it(`should succeed, when life cycle hooks are used with their corresponding interfaces`, () => { let source = ` class App extends Component implements ng.OnInit, ng.OnDestroy { diff --git a/test/usePipeTransformInterfaceRule.spec.ts b/test/usePipeTransformInterfaceRule.spec.ts index 8f15a7658..fb97eeafe 100644 --- a/test/usePipeTransformInterfaceRule.spec.ts +++ b/test/usePipeTransformInterfaceRule.spec.ts @@ -33,6 +33,16 @@ describe('use-pipe-transform-interface', () => { }`; assertSuccess('use-pipe-transform-interface', source); }); + + it(`should succeed when Pipe is declared properly`, () => { + let source = ` + @Pipe({name: 'fetch'}) + export class NewPipe implements ng.PipeTransform { + transform(url:string):any { + } + }`; + assertSuccess('use-pipe-transform-interface', source); + }); }); describe('valid use of empty class', () => {