import * as lint from 'tslint' ; import * as ts from 'typescript' ; export class Rule extends lint . Rules . AbstractRule { public static metadata : lint . IRuleMetadata = { ruleName : 'no-whitespace-in-empty-brackets' , description : 'Disallows whitespace between empty brackets (e.g. { }, [ ], ( ))' , descriptionDetails : 'Don\'t put whitespace between empty brackets' , optionsDescription : 'Not configurable.' , options : null , optionExamples : [ 'true' ] , type : 'style' , typescriptOnly : false , } ; public apply ( sourceFile ) { return this . applyWithWalker ( new Walker ( sourceFile , this . getOptions ( ) ) ) ; } } let bracketTokens = { } ; bracketTokens [ ts . SyntaxKind . OpenBraceToken ] = ts . SyntaxKind . CloseBraceToken ; bracketTokens [ ts . SyntaxKind . OpenBracketToken ] = ts . SyntaxKind . CloseBracketToken ; bracketTokens [ ts . SyntaxKind . OpenParenToken ] = ts . SyntaxKind . CloseParenToken ; let whitespaceTokens = [ ts . SyntaxKind . WhitespaceTrivia , ts . SyntaxKind . NewLineTrivia ] ; class Walker extends lint . SkippableTokenAwareRuleWalker { private scanner : ts . Scanner ; private openPosition : number ; private closingToken : ts . SyntaxKind ; private containsWhitespace : boolean ; constructor ( sourceFile , options ) { super ( sourceFile , options ) ; this . scanner = ts . createScanner ( ts . ScriptTarget . ES5 , false , ts . LanguageVariant . Standard , sourceFile . text ) ; } private reset ( ) { this . openPosition = - 1 ; this . closingToken = null ; this . containsWhitespace = false ; } public visitSourceFile ( node ) { super . visitSourceFile ( node ) ; this . scanner . setTextPos ( 0 ) ; this . reset ( ) ; lint . scanAllTokens ( this . scanner , ( scanner ) => { const currentPos = scanner . getStartPos ( ) ; const tokenKind = scanner . getToken ( ) ; if ( tokenKind in bracketTokens ) { this . openPosition = currentPos ; this . containsWhitespace = false ; this . closingToken = bracketTokens [ tokenKind ] ; return ; } if ( this . openPosition < 0 ) { return ; } if ( tokenKind === ts . SyntaxKind . WhitespaceTrivia || tokenKind === ts . SyntaxKind . NewLineTrivia ) { this . containsWhitespace = true ; return ; } if ( tokenKind === this . closingToken ) { if ( this . containsWhitespace ) { let width = scanner . getStartPos ( ) - this . openPosition + 1 ; this . addFailure ( this . createFailure ( this . openPosition , width , 'Empty brackets should not contain whitespace' , this . createWhitespaceFix ( currentPos ) ) ) ; } } this . reset ( ) ; } ) ; } createWhitespaceFix ( closePosition ) { return new lint . Fix ( Rule . metadata . ruleName , [ this . deleteText ( this . openPosition + 1 , closePosition - this . openPosition - 1 ) ] ) ; } }