blob: 400172632cc2547b3ac4aebd3e6e0912d1237e24 [file] [log] [blame]
Jack Franklin8b9aa2f2020-02-12 16:35:15 +00001'use strict';
2
3/* eslint "complexity": [ "error", 5 ] */
4
5/**
6 * @fileoverview Disallow async functions as arguments to describe
7 */
8
Tim van der Lippe16aca392020-11-13 11:37:13 +00009const createAstUtils = require('../util/ast');
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000010
Tim van der Lippe16aca392020-11-13 11:37:13 +000011module.exports = {
12 meta: {
13 type: 'problem',
14 docs: {
Tim van der Lippe0ceb4652022-01-06 14:23:36 +010015 description: 'Disallow async functions passed to describe',
16 url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-async-describe.md'
Tim van der Lippe16aca392020-11-13 11:37:13 +000017 },
Tim van der Lippe0ceb4652022-01-06 14:23:36 +010018 fixable: 'code',
19 schema: []
Tim van der Lippe16aca392020-11-13 11:37:13 +000020 },
21 create(context) {
22 const astUtils = createAstUtils(context.settings);
23 const sourceCode = context.getSourceCode();
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000024
Tim van der Lippe16aca392020-11-13 11:37:13 +000025 function isFunction(node) {
26 return (
27 node.type === 'FunctionExpression' ||
28 node.type === 'FunctionDeclaration' ||
29 node.type === 'ArrowFunctionExpression'
30 );
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000031 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000032
Tim van der Lippe16aca392020-11-13 11:37:13 +000033 function containsDirectAwait(node) {
34 if (node.type === 'AwaitExpression') {
35 return true;
36 } else if (node.type && !isFunction(node)) {
37 return Object.keys(node).some(function (key) {
38 if (Array.isArray(node[key])) {
39 return node[key].some(containsDirectAwait);
40 } else if (key !== 'parent' && node[key] && typeof node[key] === 'object') {
41 return containsDirectAwait(node[key]);
42 }
43 return false;
44 });
45 }
46 return false;
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000047 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000048
Tim van der Lippe16aca392020-11-13 11:37:13 +000049 function fixAsyncFunction(fixer, fn) {
50 if (!containsDirectAwait(fn.body)) {
51 // Remove the "async" token and all the whitespace before "function":
52 const [ asyncToken, functionToken ] = sourceCode.getFirstTokens(fn, 2);
53 return fixer.removeRange([ asyncToken.range[0], functionToken.range[0] ]);
54 }
55 return undefined;
56 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000057
Tim van der Lippe16aca392020-11-13 11:37:13 +000058 function isAsyncFunction(node) {
59 return node && (node.type === 'FunctionExpression' ||
60 node.type === 'ArrowFunctionExpression') && node.async;
61 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000062
Tim van der Lippe16aca392020-11-13 11:37:13 +000063 return {
64 CallExpression(node) {
65 const name = astUtils.getNodeName(node.callee);
66
67 if (astUtils.isDescribe(node)) {
68 const fnArg = node.arguments.slice(-1)[0];
69 if (isAsyncFunction(fnArg)) {
70 context.report({
71 node: fnArg,
72 message: `Unexpected async function in ${name}()`,
73 fix(fixer) {
74 return fixAsyncFunction(fixer, fnArg);
75 }
76 });
77 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000078 }
79 }
Tim van der Lippe16aca392020-11-13 11:37:13 +000080 };
81 }
Jack Franklin8b9aa2f2020-02-12 16:35:15 +000082};