-
Notifications
You must be signed in to change notification settings - Fork 63
/
no-mocha-arrows.js
122 lines (108 loc) · 3.96 KB
/
no-mocha-arrows.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
'use strict';
/**
* @fileoverview Disallow arrow functions as arguments to Mocha globals
* @author Paul Melnikow
*/
const createAstUtils = require('../util/ast');
function extractSourceTextByRange(sourceCode, start, end) {
return sourceCode.text.slice(start, end).trim();
}
// eslint-disable-next-line max-statements
function formatFunctionHead(sourceCode, fn) {
const arrow = sourceCode.getTokenBefore(fn.body);
const beforeArrowToken = sourceCode.getTokenBefore(arrow);
let firstToken = sourceCode.getFirstToken(fn);
let functionKeyword = 'function';
let params = extractSourceTextByRange(
sourceCode,
firstToken.range[0],
beforeArrowToken.range[1]
);
if (fn.async) {
// When 'async' specified strip the token from the params text
// and prepend it to the function keyword
params = params.slice(firstToken.range[1] - firstToken.range[0]).trim();
functionKeyword = 'async function';
// Advance firstToken pointer
firstToken = sourceCode.getTokenAfter(firstToken);
}
const beforeArrowComment = extractSourceTextByRange(
sourceCode,
beforeArrowToken.range[1],
arrow.range[0]
);
const afterArrowComment = extractSourceTextByRange(
sourceCode,
arrow.range[1],
fn.body.range[0]
);
let paramsFullText;
if (firstToken.type !== 'Punctuator') {
paramsFullText = `(${params}${beforeArrowComment})${afterArrowComment}`;
} else {
paramsFullText = `${params}${beforeArrowComment}${afterArrowComment}`;
}
return `${functionKeyword}${paramsFullText} `;
}
function fixArrowFunction(fixer, sourceCode, fn) {
if (fn.body.type === 'BlockStatement') {
// When it((...) => { ... }),
// simply replace '(...) => ' with 'function () '
return fixer.replaceTextRange(
[ fn.range[0], fn.body.range[0] ],
formatFunctionHead(sourceCode, fn)
);
}
const bodyText = sourceCode.getText(fn.body);
return fixer.replaceTextRange(
fn.range,
`${formatFunctionHead(sourceCode, fn)}{ return ${bodyText}; }`
);
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'Disallow arrow functions as arguments to mocha functions',
url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-mocha-arrows.md'
},
fixable: 'code',
schema: []
},
create(context) {
const astUtils = createAstUtils(context.settings);
const sourceCode = context.getSourceCode();
const isTestCase = astUtils.buildIsTestCaseAnswerer();
const isDescribe = astUtils.buildIsDescribeAnswerer();
const isMochaFunctionCall = astUtils.buildIsMochaFunctionCallAnswerer(
isTestCase,
isDescribe
);
return {
CallExpression(node) {
if (isMochaFunctionCall(node, context)) {
const amountOfArguments = node.arguments.length;
if (amountOfArguments > 0) {
const lastArgument =
node.arguments[amountOfArguments - 1];
if (lastArgument.type === 'ArrowFunctionExpression') {
const name = astUtils.getNodeName(node.callee);
context.report({
node,
message: `Do not pass arrow functions to ${name}()`,
fix(fixer) {
return fixArrowFunction(
fixer,
sourceCode,
lastArgument
);
}
});
}
}
}
}
};
}
};