1 | import * as ts from 'typescript';
|
2 | import * as Lint from 'tslint';
|
3 |
|
4 | import { ErrorTolerantWalker } from './utils/ErrorTolerantWalker';
|
5 | import { ExtendedMetadata } from './utils/ExtendedMetadata';
|
6 |
|
7 | export const FAILURE_STRING: string = 'Try-catch blocks must be at the top of the scope';
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export class Rule extends Lint.Rules.AbstractRule {
|
13 | public static metadata: ExtendedMetadata = {
|
14 | ruleName: 'try-catch-first',
|
15 | type: 'maintainability',
|
16 | description:
|
17 | 'Try-catch blocks must be first within the scope. ' +
|
18 | 'Try-catch blocks are transactions and should leave your program in a consistent state, no matter what happens in the try.',
|
19 | options: null,
|
20 | optionsDescription: '',
|
21 | typescriptOnly: true,
|
22 | issueClass: 'Non-SDL',
|
23 | issueType: 'Warning',
|
24 | severity: 'Important',
|
25 | level: 'Opportunity for Excellence',
|
26 | group: 'Correctness',
|
27 | recommendation: 'true,',
|
28 | commonWeaknessEnumeration: '',
|
29 | };
|
30 |
|
31 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
32 | return this.applyWithWalker(new TryCatchFirstRuleWalker(sourceFile, this.getOptions()));
|
33 | }
|
34 | }
|
35 |
|
36 | class TryCatchFirstRuleWalker extends ErrorTolerantWalker {
|
37 | private scopeKinds: ts.SyntaxKind[] = [
|
38 | ts.SyntaxKind.FunctionDeclaration,
|
39 | ts.SyntaxKind.ArrowFunction,
|
40 | ts.SyntaxKind.SourceFile,
|
41 | ts.SyntaxKind.MethodDeclaration,
|
42 | ts.SyntaxKind.GetAccessor,
|
43 | ts.SyntaxKind.SetAccessor,
|
44 | ];
|
45 |
|
46 | protected visitTryStatement(node: ts.TryStatement): void {
|
47 | this.checkAndReport(node);
|
48 | super.visitTryStatement(node);
|
49 | }
|
50 |
|
51 | private checkAndReport(node: ts.TryStatement) {
|
52 | const block = node.parent;
|
53 | const { parent } = block;
|
54 |
|
55 | const isFirst = this.scopeKinds.indexOf((parent || block).kind) !== -1;
|
56 | if (!isFirst) {
|
57 | const failureMessage = this.makeFailureMessage();
|
58 | this.addFailureAt(node.getStart(), node.getWidth(), failureMessage);
|
59 | }
|
60 | }
|
61 |
|
62 | private makeFailureMessage(): string {
|
63 | return FAILURE_STRING;
|
64 | }
|
65 | }
|