1+ /// <reference path="../../lib/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 ( ) ) ;
28+ if ( thenStatementEndLoc . line !== ( elseKeywordLoc . line - 1 ) ) {
29+ const failure = this . createFailure ( elseKeyword . getStart ( ) , elseKeyword . getWidth ( ) , 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 tryKeyword = node . getChildAt ( 0 ) ;
44+ const tryBlock = node . tryBlock ;
45+ const tryOpeningBrace = tryBlock . getChildAt ( 0 ) ;
46+
47+ if ( this . hasOption ( OPTION_CATCH ) && ! ! catchClause ) {
48+ const tryClosingBrace = node . tryBlock . getChildAt ( node . tryBlock . getChildCount ( ) - 1 ) ;
49+ const catchKeyword = catchClause . getChildAt ( 0 ) ;
50+ const tryClosingBraceLoc = sourceFile . getLineAndCharacterOfPosition ( tryClosingBrace . getEnd ( ) ) ;
51+ const catchKeywordLoc = sourceFile . getLineAndCharacterOfPosition ( catchKeyword . getStart ( ) ) ;
52+ if ( tryClosingBraceLoc . line !== ( catchKeywordLoc . line - 1 ) ) {
53+ const failure = this . createFailure ( catchKeyword . getStart ( ) , catchKeyword . getWidth ( ) , Rule . CATCH_FAILURE_STRING ) ;
54+ this . addFailure ( failure ) ;
55+ }
56+ }
57+ super . visitTryStatement ( node ) ;
58+ }
59+ }
60+
61+ function getFirstChildOfKind ( node : ts . Node , kind : ts . SyntaxKind ) {
62+ return node . getChildren ( ) . filter ( ( child ) => child . kind === kind ) [ 0 ] ;
63+ }
0 commit comments