UNPKG

3.63 kBJavaScriptView Raw
1'use strict';
2
3const {
4 getDocsUrl,
5 expectCase,
6 expectResolveCase,
7 expectRejectCase,
8 method,
9 argument,
10} = require('./util');
11
12const isEqualityCheck = node =>
13 method(node) &&
14 (method(node).name === 'toBe' || method(node).name === 'toEqual');
15
16const isArgumentValid = node =>
17 argument(node).value === true || argument(node).value === false;
18
19const hasOneArgument = node => node.arguments && node.arguments.length === 1;
20
21const isValidEqualityCheck = node =>
22 isEqualityCheck(node) &&
23 hasOneArgument(node.parent.parent) &&
24 isArgumentValid(node);
25
26const isEqualityNegation = node =>
27 method(node).name === 'not' && isValidEqualityCheck(node.parent);
28
29const hasIncludesMethod = node =>
30 node.arguments[0] &&
31 node.arguments[0].callee &&
32 node.arguments[0].callee.property &&
33 node.arguments[0].callee.property.name === 'includes';
34
35const isValidIncludesMethod = node =>
36 hasIncludesMethod(node) && hasOneArgument(node.arguments[0]);
37
38const getNegationFixes = (node, sourceCode, fixer) => {
39 const negationPropertyDot = sourceCode.getFirstTokenBetween(
40 node.parent.object,
41 node.parent.property,
42 token => token.value === '.'
43 );
44 const toContainFunc =
45 isEqualityNegation(node) && argument(node.parent).value
46 ? 'not.toContain'
47 : 'toContain';
48
49 //.includes function argument
50 const [containArg] = node.arguments[0].arguments;
51 return [
52 fixer.remove(negationPropertyDot),
53 fixer.remove(method(node)),
54 fixer.replaceText(method(node.parent), toContainFunc),
55 fixer.replaceText(argument(node.parent), sourceCode.getText(containArg)),
56 ];
57};
58
59const getCommonFixes = (node, sourceCode, fixer) => {
60 const [containArg] = node.arguments[0].arguments;
61 const includesCaller = node.arguments[0].callee;
62
63 const propertyDot = sourceCode.getFirstTokenBetween(
64 includesCaller.object,
65 includesCaller.property,
66 token => token.value === '.'
67 );
68
69 const closingParenthesis = sourceCode.getTokenAfter(containArg);
70 const openParenthesis = sourceCode.getTokenBefore(containArg);
71
72 return [
73 fixer.remove(containArg),
74 fixer.remove(includesCaller.property),
75 fixer.remove(propertyDot),
76 fixer.remove(closingParenthesis),
77 fixer.remove(openParenthesis),
78 ];
79};
80
81module.exports = {
82 meta: {
83 docs: {
84 url: getDocsUrl(__filename),
85 },
86 fixable: 'code',
87 },
88 create(context) {
89 return {
90 CallExpression(node) {
91 if (
92 !(expectResolveCase(node) || expectRejectCase(node)) &&
93 expectCase(node) &&
94 (isEqualityNegation(node) || isValidEqualityCheck(node)) &&
95 isValidIncludesMethod(node)
96 ) {
97 context.report({
98 fix(fixer) {
99 const sourceCode = context.getSourceCode();
100
101 let fixArr = getCommonFixes(node, sourceCode, fixer);
102 if (isEqualityNegation(node)) {
103 return getNegationFixes(node, sourceCode, fixer).concat(fixArr);
104 }
105
106 const toContainFunc = argument(node).value
107 ? 'toContain'
108 : 'not.toContain';
109
110 //.includes function argument
111 const [containArg] = node.arguments[0].arguments;
112
113 fixArr.push(fixer.replaceText(method(node), toContainFunc));
114 fixArr.push(
115 fixer.replaceText(
116 argument(node),
117 sourceCode.getText(containArg)
118 )
119 );
120 return fixArr;
121 },
122 message: 'Use toContain() instead',
123 node: method(node),
124 });
125 }
126 },
127 };
128 },
129};