22const getDocsUrl = require ( './utils/get-docs-url' ) ;
33const isMethodNamed = require ( './utils/is-method-named' ) ;
44
5+ // Ignore {_,lodash,underscore}.indexOf
6+ const ignoredVariables = new Set ( [ '_' , 'lodash' , 'underscore' ] ) ;
57const isNegativeOne = ( operator , value ) => operator === '-' && value === 1 ;
8+ const isIgnoredTarget = node => node . type === 'Identifier' && ignoredVariables . has ( node . name ) ;
69
7- const report = ( context , node , target , pattern ) => {
10+ const report = ( context , node , target , argumentsNodes ) => {
811 const sourceCode = context . getSourceCode ( ) ;
912 const memberExpressionNode = target . parent ;
1013 const dotToken = sourceCode . getTokenBefore ( memberExpressionNode . property ) ;
1114 const targetSource = sourceCode . getText ( ) . slice ( memberExpressionNode . range [ 0 ] , dotToken . range [ 0 ] ) ;
12- const patternSource = sourceCode . getText ( pattern ) ;
15+
16+ // Strip default `fromIndex`
17+ if ( argumentsNodes . length === 2 && argumentsNodes [ 1 ] . type === 'Literal' && argumentsNodes [ 1 ] . value === 0 ) {
18+ argumentsNodes = argumentsNodes . slice ( 0 , 1 ) ;
19+ }
20+
21+ const argumentsSource = argumentsNodes . map ( argument => sourceCode . getText ( argument ) ) ;
1322
1423 context . report ( {
1524 node,
1625 message : 'Use `.includes()`, rather than `.indexOf()`, when checking for existence.' ,
1726 fix : fixer => {
1827 const isNot = node => [ '===' , '==' , '<' ] . includes ( node . operator ) ? '!' : '' ;
19- const replacement = `${ isNot ( node ) } ${ targetSource } .includes(${ patternSource } )` ;
28+ const replacement = `${ isNot ( node ) } ${ targetSource } .includes(${ argumentsSource . join ( ', ' ) } )` ;
2029 return fixer . replaceText ( node , replacement ) ;
2130 }
2231 } ) ;
@@ -26,29 +35,39 @@ const create = context => ({
2635 BinaryExpression : node => {
2736 const { left, right} = node ;
2837
29- if ( isMethodNamed ( left , 'indexOf' ) ) {
30- const target = left . callee . object ;
31- const pattern = left . arguments [ 0 ] ;
38+ if ( ! isMethodNamed ( left , 'indexOf' ) ) {
39+ return ;
40+ }
41+
42+ const target = left . callee . object ;
3243
33- if ( right . type === 'UnaryExpression' ) {
34- const { argument} = right ;
44+ if ( isIgnoredTarget ( target ) ) {
45+ return ;
46+ }
47+
48+ const { arguments : argumentsNodes } = left ;
3549
36- if ( argument . type !== 'Literal' ) {
37- return false ;
38- }
50+ // Ignore something.indexOf(foo, 0, another)
51+ if ( argumentsNodes . length > 2 ) {
52+ return ;
53+ }
3954
40- const { value} = argument ;
55+ if ( right . type === 'UnaryExpression' ) {
56+ const { argument} = right ;
4157
42- if ( [ '!==' , '!=' , '>' , '===' , '==' ] . includes ( node . operator ) && isNegativeOne ( right . operator , value ) ) {
43- report ( context , node , target , pattern ) ;
44- }
58+ if ( argument . type !== 'Literal' ) {
59+ return ;
4560 }
4661
47- if ( right . type === 'Literal' && [ '>=' , '<' ] . includes ( node . operator ) && right . value === 0 ) {
48- report ( context , node , target , pattern ) ;
62+ const { value} = argument ;
63+
64+ if ( [ '!==' , '!=' , '>' , '===' , '==' ] . includes ( node . operator ) && isNegativeOne ( right . operator , value ) ) {
65+ report ( context , node , target , argumentsNodes ) ;
4966 }
67+ }
5068
51- return false ;
69+ if ( right . type === 'Literal' && [ '>=' , '<' ] . includes ( node . operator ) && right . value === 0 ) {
70+ report ( context , node , target , argumentsNodes ) ;
5271 }
5372 }
5473} ) ;
0 commit comments