Skip to content

Commit

Permalink
refactor(rule): rename/clean up 'no-attribute-parameter-decorator' (#781
Browse files Browse the repository at this point in the history
)
  • Loading branch information
rafaelss95 authored and mgechev committed Mar 6, 2019
1 parent 43e2d09 commit 049be66
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 137 deletions.
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { Rule as ContextualLifecycleRule } from './contextualLifecycleRule';
export { Rule as DirectiveClassSuffixRule } from './directiveClassSuffixRule';
export { Rule as DirectiveSelectorRule } from './directiveSelectorRule';
export { Rule as ImportDestructuringSpacingRule } from './importDestructuringSpacingRule';
export { Rule as NoAttributeParameterDecoratorRule } from './noAttributeParameterDecoratorRule';
export { Rule as NoAttributeDecoratorRule } from './noAttributeDecoratorRule';
export { Rule as NoConflictingLifecycleRule } from './noConflictingLifecycleRule';
export { Rule as NoForwardRefRule } from './noForwardRefRule';
export { Rule as NoHostMetadataPropertyRule } from './noHostMetadataPropertyRule';
Expand Down
61 changes: 61 additions & 0 deletions src/noAttributeDecoratorRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { IRuleMetadata, RuleFailure, WalkContext } from 'tslint';
import { AbstractRule } from 'tslint/lib/rules';
import {
ConstructorDeclaration,
Decorator,
forEachChild,
isConstructorDeclaration,
Node,
ParameterDeclaration,
SourceFile
} from 'typescript';
import { getDecoratorName } from './util/utils';

export class Rule extends AbstractRule {
static readonly metadata: IRuleMetadata = {
description: 'Disallows usage of @Attribute decorator.',
options: null,
optionsDescription: 'Not configurable.',
rationale: '@Attribute is considered bad practice. Use @Input instead.',
ruleName: 'no-attribute-decorator',
type: 'functionality',
typescriptOnly: true
};

static readonly FAILURE_STRING = '@Attribute is considered bad practice. Use @Input instead.';

apply(sourceFile: SourceFile): RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}

const isAttributeDecorator = (decorator: Decorator): boolean => getDecoratorName(decorator) === 'Attribute';

const validateConstructor = (context: WalkContext<void>, node: ConstructorDeclaration): void =>
node.parameters.forEach(parameter => validateParameter(context, parameter));

const validateDecorator = (context: WalkContext<void>, decorator: Decorator): void => {
if (!isAttributeDecorator(decorator)) return;

context.addFailureAtNode(decorator, Rule.FAILURE_STRING);
};

const validateParameter = (context: WalkContext<void>, parameter: ParameterDeclaration): void => {
const { decorators } = parameter;

if (!decorators) return;

decorators.forEach(decorator => validateDecorator(context, decorator));
};

const walk = (context: WalkContext<void>): void => {
const { sourceFile } = context;

const callback = (node: Node): void => {
if (isConstructorDeclaration(node)) validateConstructor(context, node);

forEachChild(node, callback);
};

forEachChild(sourceFile, callback);
};
58 changes: 0 additions & 58 deletions src/noAttributeParameterDecoratorRule.ts

This file was deleted.

112 changes: 112 additions & 0 deletions test/noAttributeDecoratorRule.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Rule } from '../src/noAttributeDecoratorRule';
import { assertAnnotated, assertMultipleAnnotated, assertSuccess } from './testHelper';

const {
FAILURE_STRING,
metadata: { ruleName }
} = Rule;

describe(ruleName, () => {
describe('failure', () => {
it('should fail if @Attribute decorator is used', () => {
const source = `
class Test {
label: string;
constructor(@Attribute('label') label) {
~~~~~~~~~~~~~~~~~~~
this.label = label;
}
}
`;
assertAnnotated({
message: FAILURE_STRING,
ruleName,
source
});
});

it('should fail if @Attribute decorator is used in a class expression', () => {
const source = `
class Test {
private count = 0;
InnerTestClass = new class {
constructor(@Attribute('label') label: string) {}
~~~~~~~~~~~~~~~~~~~
}(this);
}
`;
assertAnnotated({
message: FAILURE_STRING,
ruleName,
source
});
});

it('should fail if @Attribute decorator is used in a property class declaration', () => {
const source = `
class Test {
static InnerTestClass = class extends TestCase {
constructor(@Attribute('label') label: string) {}
~~~~~~~~~~~~~~~~~~~
};
}
`;
assertAnnotated({
message: FAILURE_STRING,
ruleName,
source
});
});

it('should fail if multiple @Attribute decorators are used', () => {
const source = `
class Test {
constructor(@Attribute('label') label: string) {
~~~~~~~~~~~~~~~~~~~
}
InnerTest1 = new class {
constructor(@Attribute('label') label: string) {}
^^^^^^^^^^^^^^^^^^^
}(this);
static InnerTestClass2 = class extends TestCase {
constructor(@Attribute('label') label: string) {}
###################
};
}
`;
assertMultipleAnnotated({
failures: [
{
char: '~',
msg: FAILURE_STRING
},
{
char: '^',
msg: FAILURE_STRING
},
{
char: '#',
msg: FAILURE_STRING
}
],
ruleName,
source
});
});
});

describe('success', () => {
it('should succeed if no @Attribute decorator is used', () => {
const source = `
class Test {
constructor(@Property('label') label: string) {}
}
`;
assertSuccess(ruleName, source);
});
});
});
78 changes: 0 additions & 78 deletions test/noAttributeParameterDecoratorRule.spec.ts

This file was deleted.

0 comments on commit 049be66

Please sign in to comment.