From 5f6da9b538f1b0b0aacb48c3d6c090c84cccf0a3 Mon Sep 17 00:00:00 2001 From: mgechev Date: Thu, 5 Oct 2017 10:40:32 +0200 Subject: [PATCH 1/2] fix(rules): handle anonymous class Fix #422 --- package-lock.json | 32 +++++------ src/noAttributeParameterDecoratorRule.ts | 4 +- src/util/utils.ts | 57 ++++++++++++------- .../noAttributeParameterDecoratorRule.spec.ts | 18 +++++- 4 files changed, 72 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31c381b2b..eb11f59c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,22 @@ { "name": "codelyzer", - "version": "3.1.2", + "version": "3.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@angular/compiler": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.3.2.tgz", - "integrity": "sha1-t5ItCyCHqC57UWocERpZkwVPaLM=", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-4.4.4.tgz", + "integrity": "sha1-Mm6wAp2aNUGqyhJN75rcUcNvK0E=", "dev": true, "requires": { "tslib": "1.7.1" } }, "@angular/core": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.3.2.tgz", - "integrity": "sha1-6ng0HDUBrY9DtR/7GD4gDcGYRMM=", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-4.4.4.tgz", + "integrity": "sha1-vTfs9UFY+XSJmWyThr0iL4CjL1w=", "dev": true, "requires": { "tslib": "1.7.1" @@ -1759,15 +1759,6 @@ } } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -1779,6 +1770,15 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", diff --git a/src/noAttributeParameterDecoratorRule.ts b/src/noAttributeParameterDecoratorRule.ts index 95d24dc36..2bad21163 100644 --- a/src/noAttributeParameterDecoratorRule.ts +++ b/src/noAttributeParameterDecoratorRule.ts @@ -29,9 +29,9 @@ export class Rule extends Lint.Rules.AbstractRule { const syntaxKind = SyntaxKind.current(); return Maybe.lift(node.parent) .fmap(parent => { - if (parent.kind === syntaxKind.ClassExpression) { + if (parent.kind === syntaxKind.ClassExpression && parent.parent.name) { return parent.parent.name.text; - } else if (parent.kind = syntaxKind.ClassDeclaration) { + } else if (parent.kind === syntaxKind.ClassDeclaration) { return parent.name.text; } }) diff --git a/src/util/utils.ts b/src/util/utils.ts index 730c8d6c8..8b61e2b08 100644 --- a/src/util/utils.ts +++ b/src/util/utils.ts @@ -2,7 +2,12 @@ import * as ts from 'typescript'; const SyntaxKind = require('./syntaxKind'); // Lewenshtein algorithm -export const stringDistance = (s: string, t: string, ls: number = s.length, lt: number = t.length) => { +export const stringDistance = ( + s: string, + t: string, + ls: number = s.length, + lt: number = t.length +) => { let memo = []; let currRowMemo; let i; @@ -25,19 +30,27 @@ export const stringDistance = (s: string, t: string, ls: number = s.length, lt: }; export const isSimpleTemplateString = (e: any) => { - return e.kind === ts.SyntaxKind.StringLiteral || - e.kind === SyntaxKind.current().FirstTemplateToken; + return ( + e.kind === ts.SyntaxKind.StringLiteral || + e.kind === SyntaxKind.current().FirstTemplateToken + ); }; -export const getDecoratorPropertyInitializer = (decorator: ts.Decorator, name: string) => { - return ( - (decorator.expression).arguments[0]) - .properties.map((prop: any) => { +export const getDecoratorPropertyInitializer = ( + decorator: ts.Decorator, + name: string +) => { + return ((decorator.expression) + .arguments[0]).properties + .map((prop: any) => { if (prop.name.text === name) { return prop; } return null; - }).filter((el: any) => !!el).map((prop: any) => prop.initializer).pop(); + }) + .filter((el: any) => !!el) + .map((prop: any) => prop.initializer) + .pop(); }; export const getDecoratorName = (decorator: ts.Decorator) => { @@ -47,16 +60,20 @@ export const getDecoratorName = (decorator: ts.Decorator) => { }; export const getComponentDecorator = (declaration: ts.ClassDeclaration) => { - return (declaration.decorators || []) - .filter((d: any) => { - if (!(d.expression).arguments || - !(d.expression).arguments.length || - !((d.expression).arguments[0]).properties) { - return false; - } - const name = getDecoratorName(d); - if (name === 'Component') { - return true; - } - }).pop(); + return (declaration.decorators || []) + .filter((d: any) => { + if ( + !(d.expression).arguments || + !(d.expression).arguments.length || + !((d.expression) + .arguments[0]).properties + ) { + return false; + } + const name = getDecoratorName(d); + if (name === 'Component') { + return true; + } + }) + .pop(); }; diff --git a/test/noAttributeParameterDecoratorRule.spec.ts b/test/noAttributeParameterDecoratorRule.spec.ts index ec02bd57a..4f9deae56 100644 --- a/test/noAttributeParameterDecoratorRule.spec.ts +++ b/test/noAttributeParameterDecoratorRule.spec.ts @@ -2,7 +2,23 @@ import { assertAnnotated, assertSuccess } from './testHelper'; describe('no-attribute-parameter-decorator', () => { describe('invalid class constructor', () => { - it(`should fail, when it's used attribute decorator`, () => { + it('should work with anonymous classes', () => { + const source = ` + type Constructor = new (...args: any[]) => T; + + export function MyUtils>(Base: T) { + return class extends Base { + constructor() {} + public myMethod(a, b): boolean { + + } + }; + } + ` + assertSuccess('no-attribute-parameter-decorator', source); + }); + + it('should fail, when it\'s used attribute decorator', () => { let source = ` class ButtonComponent { label: string; From d96d6cc61d71cdaef79b3620c74b25b5bae77bad Mon Sep 17 00:00:00 2001 From: mgechev Date: Thu, 5 Oct 2017 11:15:06 +0200 Subject: [PATCH 2/2] style: add missing semicolon --- test/noAttributeParameterDecoratorRule.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/noAttributeParameterDecoratorRule.spec.ts b/test/noAttributeParameterDecoratorRule.spec.ts index 4f9deae56..7401a7dd9 100644 --- a/test/noAttributeParameterDecoratorRule.spec.ts +++ b/test/noAttributeParameterDecoratorRule.spec.ts @@ -14,7 +14,7 @@ describe('no-attribute-parameter-decorator', () => { } }; } - ` + `; assertSuccess('no-attribute-parameter-decorator', source); });