Skip to content
This repository was archived by the owner on Mar 25, 2021. It is now read-only.

Commit 64fa117

Browse files
committed
Feature: Introduce new rule: newline-before-throw
1 parent 198bb5a commit 64fa117

File tree

4 files changed

+206
-0
lines changed

4 files changed

+206
-0
lines changed

src/configs/all.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ export const rules = {
201201
"match-default-export-name": true,
202202
"new-parens": true,
203203
"newline-before-return": true,
204+
"newline-before-throw": true,
204205
"newline-per-chained-call": true,
205206
"no-angle-bracket-type-assertion": true,
206207
"no-boolean-literal-compare": true,

src/rules/newlineBeforeThrowRule.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* @license
3+
* Copyright 2018 Palantir Technologies, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { getPreviousStatement } from "tsutils";
19+
import * as ts from "typescript";
20+
import * as Lint from "../index";
21+
22+
export class Rule extends Lint.Rules.AbstractRule {
23+
/* tslint:disable:object-literal-sort-keys */
24+
public static metadata: Lint.IRuleMetadata = {
25+
ruleName: "newline-before-throw",
26+
description: "Enforces blank line before throw when not the only line in the block.",
27+
rationale: "Helps maintain a readable style in your codebase.",
28+
optionsDescription: "Not configurable.",
29+
options: {},
30+
optionExamples: [true],
31+
type: "style",
32+
typescriptOnly: true,
33+
};
34+
/* tslint:enable:object-literal-sort-keys */
35+
36+
public static FAILURE_STRING = "Missing blank line before throw";
37+
38+
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
39+
return this.applyWithWalker(
40+
new NewlineBeforeThrowWalker(sourceFile, this.ruleName, undefined),
41+
);
42+
}
43+
}
44+
45+
class NewlineBeforeThrowWalker extends Lint.AbstractWalker<void> {
46+
public walk(sourceFile: ts.SourceFile) {
47+
const cb = (node: ts.Node): void => {
48+
if (node.kind === ts.SyntaxKind.ThrowStatement) {
49+
this.visitThrowStatement(node as ts.ThrowStatement);
50+
}
51+
return ts.forEachChild(node, cb);
52+
};
53+
return ts.forEachChild(sourceFile, cb);
54+
}
55+
56+
private visitThrowStatement(node: ts.ThrowStatement) {
57+
const prev = getPreviousStatement(node);
58+
if (prev === undefined) {
59+
// throw is not within a block (e.g. the only child of an IfStatement) or the first statement of the block
60+
// no need to check for preceding newline
61+
return;
62+
}
63+
64+
let start = node.getStart(this.sourceFile);
65+
let line = ts.getLineAndCharacterOfPosition(this.sourceFile, start).line;
66+
const comments = ts.getLeadingCommentRanges(this.sourceFile.text, node.pos);
67+
if (comments !== undefined) {
68+
// check for blank lines between comments
69+
for (let i = comments.length - 1; i >= 0; --i) {
70+
const endLine = ts.getLineAndCharacterOfPosition(this.sourceFile, comments[i].end)
71+
.line;
72+
if (endLine < line - 1) {
73+
return;
74+
}
75+
start = comments[i].pos;
76+
line = ts.getLineAndCharacterOfPosition(this.sourceFile, start).line;
77+
}
78+
}
79+
const prevLine = ts.getLineAndCharacterOfPosition(this.sourceFile, prev.end).line;
80+
81+
if (prevLine >= line - 1) {
82+
// Previous statement is on the same or previous line
83+
this.addFailure(start, start, Rule.FAILURE_STRING);
84+
}
85+
}
86+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
function foo(bar) {
2+
if (!bar) {
3+
throw new Error();
4+
}
5+
throw new Error();
6+
~nil [0]
7+
}
8+
9+
function foo(bar) {
10+
if (!bar) {
11+
var e = new Error();
12+
throw e;
13+
~nil [0]
14+
}
15+
16+
throw bar;
17+
}
18+
19+
function foo(bar) {
20+
if (!bar) {
21+
throw new Error();
22+
}
23+
/* multi-line
24+
~nil [0]
25+
comment */
26+
throw new Error();
27+
}
28+
29+
var fn = () => null;
30+
function foo() {
31+
fn();
32+
throw new Error();
33+
~nil [0]
34+
}
35+
36+
function foo(fn) {
37+
fn(); throw new Error();
38+
~nil [0]
39+
}
40+
41+
function foo() {
42+
throw new Error();
43+
}
44+
45+
function foo() {
46+
47+
throw new Error();
48+
}
49+
50+
function foo(bar) {
51+
if (!bar) throw new Error();
52+
}
53+
54+
function foo(bar) {
55+
let someCall;
56+
if (!bar) throw new Error();
57+
}
58+
59+
function foo(bar) {
60+
if (!bar) { throw new Error() };
61+
}
62+
63+
function foo(bar) {
64+
if (!bar) {
65+
throw new Error();
66+
}
67+
}
68+
69+
function foo(bar) {
70+
if (!bar) {
71+
throw new Error();
72+
}
73+
74+
throw bar;
75+
}
76+
77+
function foo(bar) {
78+
if (!bar) {
79+
80+
throw new Error();
81+
}
82+
}
83+
84+
function foo() {
85+
86+
// comment
87+
throw new Error();
88+
}
89+
90+
function test() {
91+
console.log("Any statement");
92+
// Any comment
93+
94+
throw new Error();
95+
}
96+
97+
function foo() {
98+
fn();
99+
// comment
100+
101+
// comment
102+
throw new Error();
103+
}
104+
105+
function bar() {
106+
"some statement";
107+
//comment
108+
~nil [0]
109+
//comment
110+
//comment
111+
throw new Error();
112+
}
113+
114+
[0]: Missing blank line before throw
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"rules": {
3+
"newline-before-throw": true
4+
}
5+
}

0 commit comments

Comments
 (0)