1 | 'use strict';
|
2 |
|
3 | const {
|
4 | getDocsUrl,
|
5 | expectCase,
|
6 | expectResolveCase,
|
7 | expectRejectCase,
|
8 | method,
|
9 | argument,
|
10 | } = require('./util');
|
11 |
|
12 | const isEqualityCheck = node =>
|
13 | method(node) &&
|
14 | (method(node).name === 'toBe' || method(node).name === 'toEqual');
|
15 |
|
16 | const isArgumentValid = node =>
|
17 | argument(node).value === true || argument(node).value === false;
|
18 |
|
19 | const hasOneArgument = node => node.arguments && node.arguments.length === 1;
|
20 |
|
21 | const isValidEqualityCheck = node =>
|
22 | isEqualityCheck(node) &&
|
23 | hasOneArgument(node.parent.parent) &&
|
24 | isArgumentValid(node);
|
25 |
|
26 | const isEqualityNegation = node =>
|
27 | method(node).name === 'not' && isValidEqualityCheck(node.parent);
|
28 |
|
29 | const 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 |
|
35 | const isValidIncludesMethod = node =>
|
36 | hasIncludesMethod(node) && hasOneArgument(node.arguments[0]);
|
37 |
|
38 | const 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 |
|
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 |
|
59 | const 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 |
|
81 | module.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 |
|
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 | };
|