1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | const astUtils = require('../util/ast');
|
10 | const { additionalSuiteNames } = require('../util/settings');
|
11 |
|
12 | module.exports = function (context) {
|
13 | const sourceCode = context.getSourceCode();
|
14 |
|
15 | function isFunction(node) {
|
16 | return (
|
17 | node.type === 'FunctionExpression' ||
|
18 | node.type === 'FunctionDeclaration' ||
|
19 | node.type === 'ArrowFunctionExpression'
|
20 | );
|
21 | }
|
22 |
|
23 | function containsDirectAwait(node) {
|
24 | if (node.type === 'AwaitExpression') {
|
25 | return true;
|
26 | } else if (node.type && !isFunction(node)) {
|
27 | return Object.keys(node).some(function (key) {
|
28 | if (Array.isArray(node[key])) {
|
29 | return node[key].some(containsDirectAwait);
|
30 | } else if (key !== 'parent' && node[key] && typeof node[key] === 'object') {
|
31 | return containsDirectAwait(node[key]);
|
32 | }
|
33 | return false;
|
34 | });
|
35 | }
|
36 | return false;
|
37 | }
|
38 |
|
39 | function fixAsyncFunction(fixer, fn) {
|
40 | if (!containsDirectAwait(fn.body)) {
|
41 |
|
42 | const [ asyncToken, functionToken ] = sourceCode.getFirstTokens(fn, 2);
|
43 | return fixer.removeRange([ asyncToken.range[0], functionToken.range[0] ]);
|
44 | }
|
45 | return undefined;
|
46 | }
|
47 |
|
48 | function isAsyncFunction(node) {
|
49 | return node && (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && node.async;
|
50 | }
|
51 |
|
52 | return {
|
53 | CallExpression(node) {
|
54 | const name = astUtils.getNodeName(node.callee);
|
55 |
|
56 | if (astUtils.isDescribe(node, additionalSuiteNames(context.settings))) {
|
57 | const fnArg = node.arguments.slice(-1)[0];
|
58 | if (isAsyncFunction(fnArg)) {
|
59 | context.report({
|
60 | node: fnArg,
|
61 | message: `Unexpected async function in ${name}()`,
|
62 | fix(fixer) {
|
63 | return fixAsyncFunction(fixer, fnArg);
|
64 | }
|
65 | });
|
66 | }
|
67 | }
|
68 | }
|
69 | };
|
70 | };
|