Skip to content

Commit

Permalink
refactor: change lifecycle to life cycle (mgechev#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelss95 authored and wKoza committed Apr 26, 2018
1 parent 06c780d commit 1a9eccb
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 137 deletions.
35 changes: 10 additions & 25 deletions src/contextualLifeCycleRule.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import { vsprintf } from 'sprintf-js';
import * as Lint from 'tslint';
import * as ts from 'typescript';
import { sprintf } from 'sprintf-js';
import SyntaxKind = require('./util/syntaxKind');
import { NgWalker } from './angular/ngWalker';
import { ComponentMetadata, DirectiveMetadata } from './angular/metadata';
import { NgWalker } from './angular/ngWalker';

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: 'contextual-life-cycle',
type: 'functionality',
static metadata: Lint.IRuleMetadata = {
description: 'Ensure that classes use allowed life cycle method in its body',
rationale: `Some life cycle methods can only be used in certain class types.
For example, ngOnInit() hook method should not be used in an @Injectable class.`,
options: null,
optionsDescription: 'Not configurable.',
rationale: `Some life cycle methods can only be used in certain class types.
For example, ngOnInit() hook method should not be used in an @Injectable class.`,
ruleName: 'contextual-life-cycle',
type: 'functionality',
typescriptOnly: true
};

static FAILURE_STRING: string = 'In the class "%s" which have the "%s" decorator, the ' +
static FAILURE_STRING = 'In the class "%s" which have the "%s" decorator, the ' +
'"%s" hook method is not allowed. ' +
'Please, drop it.';

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new ClassMetadataWalker(sourceFile, this));
}
}
Expand Down Expand Up @@ -75,89 +74,75 @@ export class ClassMetadataWalker extends NgWalker {
if (methodName === 'ngOnInit') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngOnInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngOnInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngOnChanges') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngOnChanges()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngOnChanges()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngDoCheck') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngDoCheck()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngDoCheck()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngAfterContentInit') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngAfterContentInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngAfterContentInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngAfterContentChecked') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngAfterContentChecked()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngAfterContentChecked()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngAfterViewInit') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngAfterViewInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngAfterViewInit()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}

if (methodName === 'ngAfterViewChecked') {
if (this.isInjectable) {
let failureConfig: string[] = [this.className, '@Injectable', 'ngAfterViewChecked()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
} else if (this.isPipe) {
let failureConfig: string[] = [this.className, '@Pipe', 'ngAfterViewChecked()'];
failureConfig.unshift(Rule.FAILURE_STRING);
this.generateFailure(method.getStart(), method.getWidth(), failureConfig);
}
}
}

private generateFailure(start: number, width: number, failureConfig: string[]) {
this.addFailure(this.createFailure(start, width, sprintf.apply(this, failureConfig)));
this.addFailure(this.createFailure(start, width, vsprintf(Rule.FAILURE_STRING, failureConfig)));
}
}
16 changes: 8 additions & 8 deletions src/noConflictingLifeCycleHooksRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ import * as Lint from 'tslint';
import * as ts from 'typescript';

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: 'no-conflicting-life-cycle-hooks',
type: 'maintainability',
description: 'Ensure that directives not implement conflicting lifecycle hooks.',
static metadata: Lint.IRuleMetadata = {
description: 'Ensure that directives not implement conflicting life cycle hooks.',
descriptionDetails: 'See more at https://angular.io/api/core/DoCheck#description.',
options: null,
optionsDescription: 'Not configurable.',
rationale:
'A directive typically should not use both DoCheck and OnChanges to respond ' +
'to changes on the same input, as ngOnChanges will continue to be called when the ' +
'default change detector detects changes.',
options: null,
optionsDescription: 'Not configurable.',
ruleName: 'no-conflicting-life-cycle-hooks',
type: 'maintainability',
typescriptOnly: true
};

static FAILURE_STRING = 'Implement DoCheck and OnChanges hooks in class %s is not recommended';

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new ClassMetadataWalker(sourceFile, this.getOptions()));
}
}
Expand Down Expand Up @@ -62,7 +62,7 @@ export class ClassMetadataWalker extends Lint.RuleWalker {
});

if (matchesAllHooks) {
this.addFailureAtNode(node, sprintf.apply(this, [Rule.FAILURE_STRING, node.name.text]));
this.addFailureAtNode(node, sprintf(Rule.FAILURE_STRING, node.name.text));
}
}
}
21 changes: 10 additions & 11 deletions src/noInputRenameRule.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { sprintf } from 'sprintf-js';
import * as Lint from 'tslint';
import * as ts from 'typescript';
import { sprintf } from 'sprintf-js';
import { DirectiveMetadata } from './angular/metadata';
import { NgWalker } from './angular/ngWalker';

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: 'no-input-rename',
type: 'maintainability',
static metadata: Lint.IRuleMetadata = {
description: 'Disallows renaming directive inputs by providing a string to the decorator.',
descriptionDetails: 'See more at https://angular.io/styleguide#style-05-13.',
rationale: 'Two names for the same property (one private, one public) is inherently confusing.',
options: null,
optionsDescription: 'Not configurable.',
rationale: 'Two names for the same property (one private, one public) is inherently confusing.',
ruleName: 'no-input-rename',
type: 'maintainability',
typescriptOnly: true
};

static FAILURE_STRING: string = 'In the class "%s", the directive input property "%s" should not be renamed.';
static FAILURE_STRING = 'In the class "%s", the directive input property "%s" should not be renamed.';

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new InputMetadataWalker(sourceFile, this.getOptions()));
}
}
Expand All @@ -31,14 +31,13 @@ export class InputMetadataWalker extends NgWalker {
}

visitNgInput(property: ts.PropertyDeclaration, input: ts.Decorator, args: string[]) {
const className = (property.parent as any).name.text;
const memberName = (property.name as any).text;
const className = (property.parent as ts.PropertyAccessExpression).name.getText();
const memberName = property.name.getText();

if (args.length === 0 || (this.directiveSelector && this.directiveSelector.indexOf(memberName) !== -1)) {
return;
}

const failureConfig = [Rule.FAILURE_STRING, className, memberName];
this.addFailureAtNode(property, sprintf.apply(this, failureConfig));
this.addFailureAtNode(property, sprintf(Rule.FAILURE_STRING, className, memberName));
}
}
14 changes: 7 additions & 7 deletions src/noLifeCycleCallRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import * as ts from 'typescript';
import { NgWalker } from './angular/ngWalker';

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: 'no-life-cycle-call',
type: 'maintainability',
description: 'Disallows explicit calls to lifecycle hooks.',
rationale: 'Explicit calls to lifecycle hooks could be confusing. Invoke lifecycle hooks is the responsability of Angular.',
static metadata: Lint.IRuleMetadata = {
description: 'Disallows explicit calls to life cycle hooks.',
options: null,
optionsDescription: 'Not configurable.',
rationale: 'Explicit calls to life cycle hooks could be confusing. Invoke life cycle hooks is the responsability of Angular.',
ruleName: 'no-life-cycle-call',
type: 'maintainability',
typescriptOnly: true
};

static FAILURE_STRING: string = 'Avoid explicit calls to lifecycle hooks.';
static FAILURE_STRING = 'Avoid explicit calls to life cycle hooks.';

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new ExpressionCallMetadataWalker(sourceFile, this.getOptions()));
}
}
Expand Down
28 changes: 13 additions & 15 deletions src/useLifeCycleInterfaceRule.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { sprintf } from 'sprintf-js';
import * as Lint from 'tslint';
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) {
Expand All @@ -11,22 +10,22 @@ const getInterfaceName = (t: any) => {
};

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
ruleName: 'use-life-cycle-interface',
type: 'maintainability',
static metadata: Lint.IRuleMetadata = {
description: 'Ensure that components implement life cycle interfaces if they use them.',
descriptionDetails: 'See more at https://angular.io/styleguide#style-09-01.',
rationale: 'Interfaces prescribe typed method signatures. Use those signatures to flag spelling and syntax mistakes.',
options: null,
optionsDescription: 'Not configurable.',
rationale: 'Interfaces prescribe typed method signatures. Use those signatures to flag spelling and syntax mistakes.',
ruleName: 'use-life-cycle-interface',
type: 'maintainability',
typescriptOnly: true
};

static FAILURE = 'Implement lifecycle hook interface %s for method %s in class %s (https://angular.io/styleguide#style-09-01)';
static FAILURE_STRING = 'Implement life cycle hook interface %s for method %s in class %s (https://angular.io/styleguide#style-09-01)';

static HOOKS_PREFIX = 'ng';

static LIFE_CYCLE_HOOKS_NAMES: Array<any> = [
static LIFE_CYCLE_HOOKS_NAMES: string[] = [
'OnChanges',
'OnInit',
'DoCheck',
Expand All @@ -37,25 +36,24 @@ export class Rule extends Lint.Rules.AbstractRule {
'OnDestroy'
];

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new ClassMetadataWalker(sourceFile, this.getOptions()));
}
}

export class ClassMetadataWalker extends Lint.RuleWalker {
visitClassDeclaration(node: ts.ClassDeclaration) {
let syntaxKind = SyntaxKind.current();
let className = node.name.text;
let interfaces = this.extractInterfaces(node, syntaxKind);
let methods = node.members.filter(m => m.kind === syntaxKind.MethodDeclaration);
let interfaces = this.extractInterfaces(node);
let methods = node.members.filter(m => m.kind === ts.SyntaxKind.MethodDeclaration);
this.validateMethods(methods, interfaces, className);
super.visitClassDeclaration(node);
}

private extractInterfaces(node: ts.ClassDeclaration, syntaxKind: SyntaxKind.SyntaxKind): string[] {
private extractInterfaces(node: ts.ClassDeclaration): string[] {
let interfaces: string[] = [];
if (node.heritageClauses) {
let interfacesClause = node.heritageClauses.filter(h => h.token === syntaxKind.ImplementsKeyword);
let interfacesClause = node.heritageClauses.filter(h => h.token === ts.SyntaxKind.ImplementsKeyword);
if (interfacesClause.length !== 0) {
interfaces = interfacesClause[0].types.map(getInterfaceName);
}
Expand All @@ -72,7 +70,7 @@ export class ClassMetadataWalker extends Lint.RuleWalker {
this.createFailure(
m.name.getStart(),
m.name.getWidth(),
sprintf.apply(this, [Rule.FAILURE, hookName, Rule.HOOKS_PREFIX + hookName, className])
sprintf(Rule.FAILURE_STRING, hookName, Rule.HOOKS_PREFIX + hookName, className)
)
);
}
Expand Down

0 comments on commit 1a9eccb

Please sign in to comment.