UNPKG

2.33 kBJavaScriptView Raw
1'use strict';
2const getDocumentationUrl = require('./utils/get-documentation-url');
3const isMethodNamed = require('./utils/is-method-named');
4const isLiteralValue = require('./utils/is-literal-value');
5
6const message = 'Use `.includes()`, rather than `.indexOf()`, when checking for existence.';
7// Ignore {_,lodash,underscore}.indexOf
8const ignoredVariables = new Set(['_', 'lodash', 'underscore']);
9const isIgnoredTarget = node => node.type === 'Identifier' && ignoredVariables.has(node.name);
10const isNegativeOne = node => node.type === 'UnaryExpression' && node.operator === '-' && node.argument && node.argument.type === 'Literal' && node.argument.value === 1;
11const isLiteralZero = node => isLiteralValue(node, 0);
12const isNegativeResult = node => ['===', '==', '<'].includes(node.operator);
13
14const report = (context, node, target, argumentsNodes) => {
15 const sourceCode = context.getSourceCode();
16 const memberExpressionNode = target.parent;
17 const dotToken = sourceCode.getTokenBefore(memberExpressionNode.property);
18 const targetSource = sourceCode.getText().slice(memberExpressionNode.range[0], dotToken.range[0]);
19
20 // Strip default `fromIndex`
21 if (isLiteralZero(argumentsNodes[1])) {
22 argumentsNodes = argumentsNodes.slice(0, 1);
23 }
24
25 const argumentsSource = argumentsNodes.map(argument => sourceCode.getText(argument));
26
27 context.report({
28 node,
29 message,
30 fix: fixer => {
31 const replacement = `${isNegativeResult(node) ? '!' : ''}${targetSource}.includes(${argumentsSource.join(', ')})`;
32 return fixer.replaceText(node, replacement);
33 }
34 });
35};
36
37const create = context => ({
38 BinaryExpression: node => {
39 const {left, right} = node;
40
41 if (!isMethodNamed(left, 'indexOf')) {
42 return;
43 }
44
45 const target = left.callee.object;
46
47 if (isIgnoredTarget(target)) {
48 return;
49 }
50
51 const {arguments: argumentsNodes} = left;
52
53 // Ignore something.indexOf(foo, 0, another)
54 if (argumentsNodes.length > 2) {
55 return;
56 }
57
58 if (
59 (['!==', '!=', '>', '===', '=='].includes(node.operator) && isNegativeOne(right)) ||
60 (['>=', '<'].includes(node.operator) && isLiteralZero(right))
61 ) {
62 report(
63 context,
64 node,
65 target,
66 argumentsNodes
67 );
68 }
69 }
70});
71
72module.exports = {
73 create,
74 meta: {
75 type: 'suggestion',
76 docs: {
77 url: getDocumentationUrl(__filename)
78 },
79 fixable: 'code'
80 }
81};