@@ -2,52 +2,62 @@ import * as Lint from "tslint/lib";
22import * as ts from "typescript" ;
33
44export class Rule extends Lint . Rules . AbstractRule {
5- public static FAILURE_STRING_FACTORY = ( name : string , currently : string ) => `Tag boolean argument as '${ name } ' (currently '${ currently } ')` ;
5+ public static FAILURE_STRING_FACTORY ( name : string , currently ?: string ) : string {
6+ const current = currently ? ` (currently '${ currently } ')` : "" ;
7+ return `Tag boolean argument as '${ name } '${ current } ` ;
8+ }
69
710 public apply ( sourceFile : ts . SourceFile ) : Lint . RuleFailure [ ] {
11+ // Cheat to get type checker
812 const program = ts . createProgram ( [ sourceFile . fileName ] , Lint . createCompilerOptions ( ) ) ;
913 const checker = program . getTypeChecker ( ) ;
10- return this . applyWithWalker ( new BooleanTriviaWalker ( checker , program . getSourceFile ( sourceFile . fileName ) , this . getOptions ( ) ) ) ;
14+ return this . applyWithFunction ( program . getSourceFile ( sourceFile . fileName ) , ctx => walk ( ctx , checker ) ) ;
1115 }
1216}
1317
14- class BooleanTriviaWalker extends Lint . RuleWalker {
15- constructor ( private checker : ts . TypeChecker , file : ts . SourceFile , opts : Lint . IOptions ) {
16- super ( file , opts ) ;
18+ function walk ( ctx : Lint . WalkContext < void > , checker : ts . TypeChecker ) : void {
19+ ts . forEachChild ( ctx . sourceFile , recur ) ;
20+ function recur ( node : ts . Node ) : void {
21+ if ( node . kind === ts . SyntaxKind . CallExpression ) {
22+ checkCall ( node as ts . CallExpression ) ;
23+ }
24+ ts . forEachChild ( node , recur ) ;
1725 }
1826
19- visitCallExpression ( node : ts . CallExpression ) {
20- super . visitCallExpression ( node ) ;
21- if ( node . arguments && node . arguments . some ( arg => arg . kind === ts . SyntaxKind . TrueKeyword || arg . kind === ts . SyntaxKind . FalseKeyword ) ) {
22- const targetCallSignature = this . checker . getResolvedSignature ( node ) ;
23- if ( ! ! targetCallSignature ) {
24- const targetParameters = targetCallSignature . getParameters ( ) ;
25- const source = this . getSourceFile ( ) ;
26- for ( let index = 0 ; index < targetParameters . length ; index ++ ) {
27- const param = targetParameters [ index ] ;
28- const arg = node . arguments [ index ] ;
29- if ( ! ( arg && param ) ) {
30- continue ;
31- }
32-
33- const argType = this . checker . getContextualType ( arg ) ;
34- if ( argType && ( argType . getFlags ( ) & ts . TypeFlags . Boolean ) ) {
35- if ( arg . kind !== ts . SyntaxKind . TrueKeyword && arg . kind !== ts . SyntaxKind . FalseKeyword ) {
36- continue ;
37- }
38- let triviaContent : string ;
39- const ranges = ts . getLeadingCommentRanges ( arg . getFullText ( ) , 0 ) ;
40- if ( ranges && ranges . length === 1 && ranges [ 0 ] . kind === ts . SyntaxKind . MultiLineCommentTrivia ) {
41- triviaContent = arg . getFullText ( ) . slice ( ranges [ 0 ] . pos + 2 , ranges [ 0 ] . end - 2 ) ; // +/-2 to remove /**/
42- }
43-
44- const paramName = param . getName ( ) ;
45- if ( triviaContent !== paramName && triviaContent !== paramName + ":" ) {
46- this . addFailure ( this . createFailure ( arg . getStart ( source ) , arg . getWidth ( source ) , Rule . FAILURE_STRING_FACTORY ( param . getName ( ) , triviaContent ) ) ) ;
47- }
48- }
27+ function checkCall ( node : ts . CallExpression ) : void {
28+ if ( ! node . arguments || ! node . arguments . some ( arg => arg . kind === ts . SyntaxKind . TrueKeyword || arg . kind === ts . SyntaxKind . FalseKeyword ) ) {
29+ return ;
30+ }
31+
32+ const targetCallSignature = checker . getResolvedSignature ( node ) ;
33+ if ( ! targetCallSignature ) {
34+ return ;
35+ }
36+
37+ const targetParameters = targetCallSignature . getParameters ( ) ;
38+ for ( let index = 0 ; index < targetParameters . length ; index ++ ) {
39+ const param = targetParameters [ index ] ;
40+ const arg = node . arguments [ index ] ;
41+ if ( ! ( arg && param ) ) {
42+ continue ;
43+ }
44+
45+ const argType = checker . getContextualType ( arg ) ;
46+ if ( argType && ( argType . getFlags ( ) & ts . TypeFlags . Boolean ) ) {
47+ if ( arg . kind !== ts . SyntaxKind . TrueKeyword && arg . kind !== ts . SyntaxKind . FalseKeyword ) {
48+ continue ;
49+ }
50+ let triviaContent : string | undefined ;
51+ const ranges = ts . getLeadingCommentRanges ( arg . getFullText ( ) , 0 ) ;
52+ if ( ranges && ranges . length === 1 && ranges [ 0 ] . kind === ts . SyntaxKind . MultiLineCommentTrivia ) {
53+ triviaContent = arg . getFullText ( ) . slice ( ranges [ 0 ] . pos + 2 , ranges [ 0 ] . end - 2 ) ; // +/-2 to remove /**/
54+ }
55+
56+ const paramName = param . getName ( ) ;
57+ if ( triviaContent !== paramName && triviaContent !== paramName + ":" ) {
58+ ctx . addFailureAtNode ( arg , Rule . FAILURE_STRING_FACTORY ( param . getName ( ) , triviaContent ) ) ;
4959 }
5060 }
5161 }
5262 }
53- }
63+ }
0 commit comments