Skip to content

Commit

Permalink
feat(rules): added rule orthodox-getter-and-setter (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg Ulyanov authored and pimenovoleg committed Oct 18, 2018
1 parent f890ea6 commit a92875f
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/configs/custom-rules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const customRules = {
rules: {
'orthodox-getter-and-setter': true,
'blank-lines': [
true,
{
Expand Down
75 changes: 75 additions & 0 deletions src/rules/orthodoxGetterAndSetterRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as Lint from 'tslint';
import * as tsutils from 'tsutils';
import * as ts from 'typescript';


/**
* Rule that enforces order getter property > setter property > private _property .
*/
export class Rule extends Lint.Rules.AbstractRule {
apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new Walker(sourceFile, this.getOptions()));
}
}

class Walker extends Lint.RuleWalker {
visitGetAccessor(getter: ts.GetAccessorDeclaration) {
if (getter.parent && tsutils.isClassDeclaration(getter.parent)) {
const getterName = getter.name.getText();

const setter = getter.parent.members.find((member) => {
return tsutils.isSetAccessorDeclaration(member) && member.name.getText() === getterName;
}) as ts.SetAccessorDeclaration | undefined;

if (setter && setter.pos < getter.pos) {
this.addFailureAtNode(getter, 'Getters must be declared before setters.');
}
}

super.visitGetAccessor(getter);
}

visitSetAccessor(setter: ts.SetAccessorDeclaration) {
if (setter.parent && tsutils.isClassDeclaration(setter.parent)) {
const setterName = setter.name.getText();

const getter = setter.parent.members.find((member) => {
return tsutils.isGetAccessorDeclaration(member) && member.name.getText() === setterName;
}) as ts.GetAccessorDeclaration | undefined;

if (getter && getter.pos > setter.pos) {
this.addFailureAtNode(setter, 'Setters must be declared after getters.');
}
}

super.visitSetAccessor(setter);
}

visitPropertyDeclaration(property: ts.PropertyDeclaration) {
const propertyName = property.name.getText();
const getterOrSetterName = propertyName.slice(1);

if (propertyName.startsWith('_') && tsutils.hasModifier(property.modifiers, ts.SyntaxKind.PrivateKeyword)) {
const getter = property.parent.members.find((member) => {
return tsutils.isGetAccessorDeclaration(member) && member.name.getText() === getterOrSetterName;
}) as ts.GetAccessorDeclaration | undefined;

const setter = property.parent.members.find((member) => {
return tsutils.isSetAccessorDeclaration(member) && member.name.getText() === getterOrSetterName;
}) as ts.SetAccessorDeclaration | undefined;

if (!getter && !setter) {
this.addFailureAtNode(property,
'Private property with leading underscore must be used only for getter or setter.');
}

if ((getter && property.pos < getter.pos) ||
(setter && property && property.pos < setter.pos)) {
this.addFailureAtNode(property,
'Private property for getter or setter must be declared after them.');
}
}

super.visitPropertyDeclaration(property);
}
}
100 changes: 100 additions & 0 deletions test/rules/orthodox-getter-and-setter/default/test.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
class Test1 {
get property() {
return this._property;
}

set property(value) {
this._property = value;
}

private _property: string;
}

class Test2 {
set property(value) {
~~~~~~~~~~~~~~~~~~~~~
this._property = value;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~ [Setters must be declared after getters.]

get property() {
~~~~~~~~~~~~~~~~
return this._property;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~ [Getters must be declared before setters.]

private _property: string;
}

class Test3 {
private _property: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [Private property for getter or setter must be declared after them.]

get property() {
return this._property;
}

set property(value) {
this._property = value;
}
}

class Test4 {
private _property: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [Private property for getter or setter must be declared after them.]

set property(value) {
this._property = value;
}
}

class Test5 {
private _property: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [Private property for getter or setter must be declared after them.]

get property() {
return this._property;
}
}

class Test6 {
private _property: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [Private property with leading underscore must be used only for getter or setter.]
}

class Test7 {
set property(value) {
this._property = value;
}

private _property: string;
}

class Test8 {
get property() {
return this._property;
}

private _property: string;
}

class Test9 {
private _property: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~ [Private property for getter or setter must be declared after them.]

set property(value) {
~~~~~~~~~~~~~~~~~~~~~
this._property = value;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~ [Setters must be declared after getters.]

get property() {
~~~~~~~~~~~~~~~~
return this._property;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
~~~~~ [Getters must be declared before setters.]
}
5 changes: 5 additions & 0 deletions test/rules/orthodox-getter-and-setter/default/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"orthodox-getter-and-setter": true
}
}

0 comments on commit a92875f

Please sign in to comment.