1 | 'use strict';
|
2 |
|
3 | const {visitIf} = require('enhance-visitors');
|
4 | const MicroSpellingCorrecter = require('micro-spelling-correcter');
|
5 | const util = require('../util');
|
6 | const createAvaRule = require('../create-ava-rule');
|
7 |
|
8 | const properties = new Set([
|
9 | ...util.executionMethods,
|
10 | 'context',
|
11 | 'title',
|
12 | 'skip',
|
13 | ]);
|
14 |
|
15 | const correcter = new MicroSpellingCorrecter([...properties]);
|
16 |
|
17 | const isCallExpression = node =>
|
18 | node.parent.type === 'CallExpression'
|
19 | && node.parent.callee === node;
|
20 |
|
21 | const getMemberNodes = node => {
|
22 | if (node.object.type === 'MemberExpression') {
|
23 | return [...getMemberNodes(node.object), node.property];
|
24 | }
|
25 |
|
26 | return [node.property];
|
27 | };
|
28 |
|
29 | const create = context => {
|
30 | const ava = createAvaRule();
|
31 |
|
32 | return ava.merge({
|
33 | CallExpression: visitIf([
|
34 | ava.isInTestFile,
|
35 | ava.isInTestNode,
|
36 | ])(node => {
|
37 | if (node.callee.type !== 'MemberExpression'
|
38 | && node.callee.name === 't') {
|
39 | context.report({
|
40 | node,
|
41 | message: '`t` is not a function.',
|
42 | });
|
43 | }
|
44 | }),
|
45 | MemberExpression: visitIf([
|
46 | ava.isInTestFile,
|
47 | ava.isInTestNode,
|
48 | ])(node => {
|
49 | if (node.parent.type === 'MemberExpression'
|
50 | || util.getNameOfRootNodeObject(node) !== 't') {
|
51 | return;
|
52 | }
|
53 |
|
54 | const members = getMemberNodes(node);
|
55 |
|
56 | const skipPositions = [];
|
57 | let hadCall = false;
|
58 | for (const [i, member] of members.entries()) {
|
59 | const {name} = member;
|
60 |
|
61 | let corrected = correcter.correct(name);
|
62 |
|
63 | if (i !== 0 && (corrected === 'context' || corrected === 'title')) {
|
64 | corrected = undefined;
|
65 | }
|
66 |
|
67 | if (corrected !== name) {
|
68 | if (corrected === undefined) {
|
69 | if (isCallExpression(node)) {
|
70 | context.report({
|
71 | node,
|
72 | message: `Unknown assertion method \`.${name}\`.`,
|
73 | });
|
74 | } else {
|
75 | context.report({
|
76 | node,
|
77 | message: `Unknown member \`.${name}\`. Use \`.context.${name}\` instead.`,
|
78 | });
|
79 | }
|
80 | } else {
|
81 | context.report({
|
82 | node,
|
83 | message: `Misspelled \`.${corrected}\` as \`.${name}\`.`,
|
84 | fix: fixer => fixer.replaceText(member, corrected),
|
85 | });
|
86 | }
|
87 |
|
88 | return;
|
89 | }
|
90 |
|
91 | if (name === 'context' || name === 'title') {
|
92 | if (members.length === 1 && isCallExpression(node)) {
|
93 | context.report({
|
94 | node,
|
95 | message: `Unknown assertion method \`.${name}\`.`,
|
96 | });
|
97 | }
|
98 |
|
99 | return;
|
100 | }
|
101 |
|
102 | if (name === 'skip') {
|
103 | skipPositions.push(i);
|
104 | } else {
|
105 | if (hadCall) {
|
106 | context.report({
|
107 | node,
|
108 | message: 'Can\'t chain assertion methods.',
|
109 | });
|
110 | }
|
111 |
|
112 | hadCall = true;
|
113 | }
|
114 | }
|
115 |
|
116 | if (!hadCall) {
|
117 | context.report({
|
118 | node,
|
119 | message: 'Missing assertion method.',
|
120 | });
|
121 | }
|
122 |
|
123 | if (skipPositions.length > 1) {
|
124 | context.report({
|
125 | node,
|
126 | message: 'Too many chained uses of `.skip`.',
|
127 | fix(fixer) {
|
128 | const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip'];
|
129 | return fixer.replaceText(node, chain.join('.'));
|
130 | },
|
131 | });
|
132 | }
|
133 |
|
134 | if (skipPositions.length === 1 && skipPositions[0] !== members.length - 1) {
|
135 | context.report({
|
136 | node,
|
137 | message: '`.skip` modifier should be the last in chain.',
|
138 | fix(fixer) {
|
139 | const chain = ['t', ...members.map(member => member.name).filter(name => name !== 'skip'), 'skip'];
|
140 | return fixer.replaceText(node, chain.join('.'));
|
141 | },
|
142 | });
|
143 | }
|
144 | }),
|
145 | });
|
146 | };
|
147 |
|
148 | module.exports = {
|
149 | create,
|
150 | meta: {
|
151 | type: 'problem',
|
152 | docs: {
|
153 | description: 'Disallow the incorrect use of `t`.',
|
154 | url: util.getDocsUrl(__filename),
|
155 | },
|
156 | fixable: 'code',
|
157 | schema: [],
|
158 | },
|
159 | };
|