Skip to content

Commit b4c6c1b

Browse files
cheeZeryajafff
authored andcommitted
Add ignore-constructor option to early-exit rule (#97)
1 parent a9b05fe commit b4c6c1b

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

rules/earlyExitRule.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import { isBlock, isCaseOrDefaultClause, isIfStatement } from 'tsutils';
1+
import { isBlock, isCaseOrDefaultClause, isIfStatement, isFunctionScopeBoundary } from 'tsutils';
22
import * as Lint from 'tslint';
33
import * as ts from 'typescript';
44

55
export class Rule extends Lint.Rules.AbstractRule {
66
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
7-
const options = { 'max-length': 2, ...this.ruleArguments[0] };
7+
const options = {
8+
'max-length': 2,
9+
'ignore-constructor': false,
10+
...this.ruleArguments[0],
11+
};
812
return this.applyWithFunction(sourceFile, walk, options);
913
}
1014
}
@@ -23,14 +27,19 @@ function failureStringAlways(exit: string): string {
2327

2428
interface IOptions {
2529
'max-length': number;
30+
'ignore-constructor': boolean;
2631
}
2732

2833
function walk(ctx: Lint.WalkContext<IOptions>) {
29-
const { sourceFile, options: { 'max-length': maxLineLength } } = ctx;
34+
const {
35+
sourceFile,
36+
options: { 'max-length': maxLineLength, 'ignore-constructor': ignoreConstructor },
37+
} = ctx;
3038

3139
return ts.forEachChild(sourceFile, function cb(node): void {
32-
if (isIfStatement(node))
40+
if (isIfStatement(node) && (!ignoreConstructor || !isConstructorClosestFunctionScopeBoundary(node)))
3341
check(node);
42+
3443
return ts.forEachChild(node, cb);
3544
});
3645

@@ -154,3 +163,13 @@ function isLastStatement(ifStatement: ts.IfStatement, statements: ReadonlyArray<
154163
i--;
155164
}
156165
}
166+
167+
function isConstructorClosestFunctionScopeBoundary(node: ts.Node): boolean {
168+
let currentParent = node.parent;
169+
while (currentParent) {
170+
if (isFunctionScopeBoundary(currentParent))
171+
return currentParent.kind === ts.SyntaxKind.Constructor;
172+
currentParent = currentParent.parent;
173+
}
174+
return false;
175+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
class Foo {
2+
constructor() {
3+
if (so) {
4+
blah();
5+
}
6+
}
7+
}
8+
9+
class Foo {
10+
constructor() {
11+
if (so) {
12+
two(
13+
lines);
14+
}
15+
}
16+
}
17+
18+
class Foo {
19+
constructor() {
20+
if (so) {
21+
some(
22+
long,
23+
thing);
24+
}
25+
}
26+
}
27+
28+
class Foo {
29+
constructor() {
30+
function f() {
31+
if (so) {
32+
~~ [0]
33+
some(
34+
long,
35+
thing);
36+
}
37+
38+
function f() {
39+
if (so) {
40+
~~ [0]
41+
some(
42+
long,
43+
thing);
44+
}
45+
}
46+
}
47+
}
48+
}
49+
50+
// Making sure that if statement outside function scope doesn't cause error
51+
if (so) {
52+
some(
53+
long,
54+
thing);
55+
}
56+
57+
[0]: Remainder of block is inside 'if' statement. Prefer to invert the condition and 'return' early.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"rulesDirectory": "../../../../rules",
3+
"rules": {
4+
"early-exit": [true, { "ignore-constructor": true }]
5+
}
6+
}

0 commit comments

Comments
 (0)