Skip to content

Commit

Permalink
fix(rules): handle anonymous class (#423)
Browse files Browse the repository at this point in the history
* fix(rules): handle anonymous class

Fix #422

* style: add missing semicolon
  • Loading branch information
mgechev authored Oct 5, 2017
1 parent 58cacc5 commit 61d11db
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 39 deletions.
32 changes: 16 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/noAttributeParameterDecoratorRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
})
Expand Down
57 changes: 37 additions & 20 deletions src/util/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 (<ts.ObjectLiteralExpression>
(<ts.CallExpression>decorator.expression).arguments[0])
.properties.map((prop: any) => {
export const getDecoratorPropertyInitializer = (
decorator: ts.Decorator,
name: string
) => {
return (<ts.ObjectLiteralExpression>(<ts.CallExpression>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) => {
Expand All @@ -47,16 +60,20 @@ export const getDecoratorName = (decorator: ts.Decorator) => {
};

export const getComponentDecorator = (declaration: ts.ClassDeclaration) => {
return (<ts.Decorator[]>declaration.decorators || [])
.filter((d: any) => {
if (!(<ts.CallExpression>d.expression).arguments ||
!(<ts.CallExpression>d.expression).arguments.length ||
!(<ts.ObjectLiteralExpression>(<ts.CallExpression>d.expression).arguments[0]).properties) {
return false;
}
const name = getDecoratorName(d);
if (name === 'Component') {
return true;
}
}).pop();
return (<ts.Decorator[]>declaration.decorators || [])
.filter((d: any) => {
if (
!(<ts.CallExpression>d.expression).arguments ||
!(<ts.CallExpression>d.expression).arguments.length ||
!(<ts.ObjectLiteralExpression>(<ts.CallExpression>d.expression)
.arguments[0]).properties
) {
return false;
}
const name = getDecoratorName(d);
if (name === 'Component') {
return true;
}
})
.pop();
};
18 changes: 17 additions & 1 deletion test/noAttributeParameterDecoratorRule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = new (...args: any[]) => T;
export function MyUtils<T extends Constructor<{}>>(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;
Expand Down

0 comments on commit 61d11db

Please sign in to comment.