1+ /// <reference path="../../node_modules/tslint/typings/typescriptServices.d.ts" />
2+ /// <reference path="../../node_modules/tslint/lib/tslint.d.ts" />
3+
4+ const OPTION_CATCH = "check-catch" ;
5+ const OPTION_ELSE = "check-else" ;
6+
7+ export class Rule extends Lint . Rules . AbstractRule {
8+ public static CATCH_FAILURE_STRING = "'catch' should be on the line following the previous block's ending curly brace" ;
9+ public static ELSE_FAILURE_STRING = "'else' should be on the line following the previous block's ending curly brace" ;
10+
11+ public apply ( sourceFile : ts . SourceFile ) : Lint . RuleFailure [ ] {
12+ return this . applyWithWalker ( new NextLineWalker ( sourceFile , this . getOptions ( ) ) ) ;
13+ }
14+ }
15+
16+ class NextLineWalker extends Lint . RuleWalker {
17+ public visitIfStatement ( node : ts . IfStatement ) {
18+ const sourceFile = node . getSourceFile ( ) ;
19+ const thenStatement = node . thenStatement ;
20+
21+ const elseStatement = node . elseStatement ;
22+ if ( ! ! elseStatement ) {
23+ // find the else keyword
24+ const elseKeyword = getFirstChildOfKind ( node , ts . SyntaxKind . ElseKeyword ) ;
25+ if ( this . hasOption ( OPTION_ELSE ) && ! ! elseKeyword ) {
26+ const thenStatementEndLoc = sourceFile . getLineAndCharacterOfPosition ( thenStatement . getEnd ( ) ) ;
27+ const elseKeywordLoc = sourceFile . getLineAndCharacterOfPosition ( elseKeyword . getStart ( sourceFile ) ) ;
28+ if ( thenStatementEndLoc . line !== ( elseKeywordLoc . line - 1 ) ) {
29+ const failure = this . createFailure ( elseKeyword . getStart ( sourceFile ) , elseKeyword . getWidth ( sourceFile ) , Rule . ELSE_FAILURE_STRING ) ;
30+ this . addFailure ( failure ) ;
31+ }
32+ }
33+ }
34+
35+ super . visitIfStatement ( node ) ;
36+ }
37+
38+ public visitTryStatement ( node : ts . TryStatement ) {
39+ const sourceFile = node . getSourceFile ( ) ;
40+ const catchClause = node . catchClause ;
41+
42+ // "visit" try block
43+ const tryBlock = node . tryBlock ;
44+
45+ if ( this . hasOption ( OPTION_CATCH ) && ! ! catchClause ) {
46+ const tryClosingBrace = tryBlock . getLastToken ( sourceFile ) ;
47+ const catchKeyword = catchClause . getFirstToken ( sourceFile ) ;
48+ const tryClosingBraceLoc = sourceFile . getLineAndCharacterOfPosition ( tryClosingBrace . getEnd ( ) ) ;
49+ const catchKeywordLoc = sourceFile . getLineAndCharacterOfPosition ( catchKeyword . getStart ( sourceFile ) ) ;
50+ if ( tryClosingBraceLoc . line !== ( catchKeywordLoc . line - 1 ) ) {
51+ const failure = this . createFailure ( catchKeyword . getStart ( sourceFile ) , catchKeyword . getWidth ( sourceFile ) , Rule . CATCH_FAILURE_STRING ) ;
52+ this . addFailure ( failure ) ;
53+ }
54+ }
55+ super . visitTryStatement ( node ) ;
56+ }
57+ }
58+
59+ function getFirstChildOfKind ( node : ts . Node , kind : ts . SyntaxKind ) {
60+ return node . getChildren ( ) . filter ( ( child ) => child . kind === kind ) [ 0 ] ;
61+ }
0 commit comments