import * as ts from 'typescript' ; import * as Lint from 'tslint' ; import { endsControlFlow } from '../../util/control-flow' ; import { convertAst } from '../../util/convert-ast' ; import { isBlockLike , isIterationStatement , isWithStatement , isIfStatement , isLabeledStatement } from '../../typeguard/node' ; export class Rule extends Lint . Rules . OptionallyTypedRule { public apply ( sourceFile ) { return this . applyWithFunction ( sourceFile , walk ) ; } public applyWithProgram ( sourceFile , program ) { return this . applyWithFunction ( sourceFile , walk , undefined , program . getTypeChecker ( ) ) ; } } function walk ( ctx , checker ? ) { const seen = new Set < ts . Node > ( ) ; for ( const node of convertAst ( ctx . sourceFile ) . flat ) { if ( isBlockLike ( node ) ) { checkStatement ( node ) ; node . statements . forEach ( checkStatement ) ; } else if ( isIterationStatement ( node ) || isWithStatement ( node ) || isLabeledStatement ( node ) ) { checkStatement ( node . statement ) ; } else if ( isIfStatement ( node ) ) { checkStatement ( node . thenStatement ) ; if ( node . elseStatement ) checkStatement ( node . elseStatement ) ; } } function checkStatement ( node ) { if ( seen . has ( node ) ) return ; seen . add ( node ) ; if ( endsControlFlow ( node , checker ) ) ctx . addFailureAtNode ( node . getFirstToken ( ctx . sourceFile ) ! , 'control flow end' ) ; } }