'use strict'; /** * @fileoverview Disallow arrow functions as arguments to Mocha globals * @author Paul Melnikow */ const createAstUtils = require('../util/ast'); module.exports = { meta: { type: 'suggestion', docs: { description: 'Disallow arrow functions as arguments to mocha functions' }, fixable: 'code' }, create(context) { const astUtils = createAstUtils(context.settings); const sourceCode = context.getSourceCode(); function extractSourceTextByRange(start, end) { return sourceCode.text.slice(start, end).trim(); } // eslint-disable-next-line max-statements function formatFunctionHead(fn) { const arrow = sourceCode.getTokenBefore(fn.body); const beforeArrowToken = sourceCode.getTokenBefore(arrow); let firstToken = sourceCode.getFirstToken(fn); let functionKeyword = 'function'; let params = extractSourceTextByRange(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(beforeArrowToken.range[1], arrow.range[0]); const afterArrowComment = extractSourceTextByRange(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, fn) { if (fn.body.type === 'BlockStatement') { // When it((...) => { ... }), // simply replace '(...) => ' with 'function () ' return fixer.replaceTextRange( [ fn.range[0], fn.body.range[0] ], formatFunctionHead(fn) ); } const bodyText = sourceCode.text.slice(fn.body.range[0], fn.body.range[1]); return fixer.replaceTextRange( [ fn.range[0], fn.range[1] ], `${formatFunctionHead(fn)}{ return ${ bodyText }; }` ); } return { CallExpression(node) { const name = astUtils.getNodeName(node.callee); if (astUtils.isMochaFunctionCall(node, context.getScope())) { const fnArg = node.arguments.slice(-1)[0]; if (fnArg && fnArg.type === 'ArrowFunctionExpression') { context.report({ node, message: `Do not pass arrow functions to ${ name }()`, fix(fixer) { return fixArrowFunction(fixer, fnArg); } }); } } } }; } };