eslint-plugin-mocha
Version:
Eslint rules for mocha.
263 lines • 11.7 kB
JavaScript
import { getAllCustomNameDetails, getCustomNameDetailsForInterface } from "../mocha/all-name-details.js";
import { getAdditionalNames, getInterface } from "../settings.js";
import { findMochaVariableCalls } from "./find-mocha-variable-calls.js";
import { getFunctionExpressionLastArgument } from "./function-expression-arguments.js";
import { createListenerRecord } from "./listener-record.js";
import { expectCallExpression } from "./node-types.js";
const mochaEntityKind = {
Config: 'config',
TestCase: 'testCase',
Suite: 'suite',
Hook: 'hook'
};
const mochaEntityKinds = {
config: mochaEntityKind.Config,
testCase: mochaEntityKind.TestCase,
suite: mochaEntityKind.Suite,
hook: mochaEntityKind.Hook
};
function getMochaEntityKind(type) {
return mochaEntityKinds[type];
}
function createContext(reference) {
return {
name: reference.name,
node: reference.node,
type: reference.nameDetails.type,
config: reference.nameDetails.config,
modifier: reference.nameDetails.modifier,
interface: reference.nameDetails.interface
};
}
function createCachedMochaCall(reference) {
return {
kind: getMochaEntityKind(reference.nameDetails.type),
reference
};
}
function createMochaCallCache(references) {
const cache = new WeakMap();
for (const reference of references) {
cache.set(reference.node, createCachedMochaCall(reference));
}
return cache;
}
function createCallExpressionDispatchGroup(visitor, callbackVisitor, suiteOrTestCaseVisitor) {
if (visitor === undefined && callbackVisitor === undefined && suiteOrTestCaseVisitor === undefined) {
return undefined;
}
return {
visitor,
callbackVisitor,
suiteOrTestCaseVisitor
};
}
function dispatchCallback(visitor, context) {
const callbackNode = getFunctionExpressionLastArgument(expectCallExpression(context.node));
if (callbackNode !== undefined) {
const callbackContext = { ...context, node: callbackNode };
visitor?.(callbackContext);
}
}
function dispatchSpecificCallExpressionContext(group, context) {
if (group === undefined) {
return;
}
group.visitor?.(context);
group.suiteOrTestCaseVisitor?.(context);
dispatchCallback(group.callbackVisitor, context);
}
function dispatchCallExpressionContext(kind, group, dispatchers, cachedMochaCall) {
const context = createContext(cachedMochaCall.reference);
if (kind === mochaEntityKind.Config) {
group?.visitor?.(context);
return;
}
dispatchSpecificCallExpressionContext(group, context);
dispatchers.anyTestEntity?.(context);
dispatchCallback(dispatchers.anyTestEntityCallback, context);
}
function createCallExpressionDispatcher(dispatchers) {
const groups = {
[mochaEntityKind.Config]: createCallExpressionDispatchGroup(dispatchers.config, undefined, undefined),
[mochaEntityKind.TestCase]: createCallExpressionDispatchGroup(dispatchers.testCase, dispatchers.testCaseCallback, dispatchers.suiteOrTestCase),
[mochaEntityKind.Suite]: createCallExpressionDispatchGroup(dispatchers.suite, dispatchers.suiteCallback, dispatchers.suiteOrTestCase),
[mochaEntityKind.Hook]: createCallExpressionDispatchGroup(dispatchers.hook, dispatchers.hookCallback, undefined)
};
const hasDispatcher = [
groups[mochaEntityKind.Config],
groups[mochaEntityKind.TestCase],
groups[mochaEntityKind.Suite],
groups[mochaEntityKind.Hook],
dispatchers.anyTestEntity,
dispatchers.anyTestEntityCallback
]
.some(function (dispatcher) {
return dispatcher !== undefined;
});
if (!hasDispatcher) {
return undefined;
}
return function (cachedMochaCall) {
dispatchCallExpressionContext(cachedMochaCall.kind, groups[cachedMochaCall.kind], dispatchers, cachedMochaCall);
};
}
function callExpressionVisitor(cachedMochaCallsByNode, node, listenerSet) {
const { mocha, nonMocha, generic } = listenerSet;
const cachedMochaCall = cachedMochaCallsByNode.get(node);
if (cachedMochaCall === undefined) {
nonMocha?.(node);
}
else {
mocha?.(cachedMochaCall);
}
generic?.(node);
}
function expressionVisitor(cachedMochaCallsByNode, node, listenerSet) {
const { mocha, nonMocha, generic } = listenerSet;
if (cachedMochaCallsByNode.has(node.parent)) {
mocha?.(node);
}
else {
nonMocha?.(node);
}
generic?.(node);
}
const cachedCalls = new Map();
// eslint-disable-next-line max-statements -- caching with two cache keys, requires weird dance of statements
function findCallsCached(context, options) {
const settingsCacheKey = JSON.stringify({
settings: context.settings,
includeAllInterfaces: options.includeAllInterfaces === true
});
let callsPerSettings = cachedCalls.get(settingsCacheKey);
if (callsPerSettings === undefined) {
callsPerSettings = new WeakMap();
cachedCalls.set(settingsCacheKey, callsPerSettings);
}
const callCacheKey = context.sourceCode;
let cachedMochaCallsByNode = callsPerSettings.get(callCacheKey);
if (cachedMochaCallsByNode === undefined) {
const additionalCustomNames = getAdditionalNames(context.settings);
const interfaceToUse = getInterface(context.settings);
const includeAllInterfaces = options.includeAllInterfaces === true;
const customNames = includeAllInterfaces
? getAllCustomNameDetails(additionalCustomNames)
: getCustomNameDetailsForInterface(additionalCustomNames, interfaceToUse);
const calls = findMochaVariableCalls(context, customNames, interfaceToUse, includeAllInterfaces);
cachedMochaCallsByNode = createMochaCallCache(calls);
callsPerSettings.set(callCacheKey, cachedMochaCallsByNode);
}
return cachedMochaCallsByNode;
}
function splitMochaVisitors(visitors) {
const { nonMochaCallExpression, 'nonMochaCallExpression:exit': nonMochaCallExpressionExit, mochaMemberExpression, nonMochaMemberExpression, 'mochaMemberExpression:exit': mochaMemberExpressionExit, 'nonMochaMemberExpression:exit': nonMochaMemberExpressionExit, mochaFunctionExpression, nonMochaFunctionExpression, 'mochaFunctionExpression:exit': mochaFunctionExpressionExit, 'nonMochaFunctionExpression:exit': nonMochaFunctionExpressionExit, config, 'config:exit': configExit, testCase, 'testCase:exit': testCaseExit, testCaseCallback, 'testCaseCallback:exit': testCaseCallbackExit, suite, 'suite:exit': suiteExit, suiteCallback, 'suiteCallback:exit': suiteCallbackExit, hook, 'hook:exit': hookExit, hookCallback, 'hookCallback:exit': hookCallbackExit, suiteOrTestCase, 'suiteOrTestCase:exit': suiteOrTestCaseExit, anyTestEntity, 'anyTestEntity:exit': anyTestEntityExit, anyTestEntityCallback, 'anyTestEntityCallback:exit': anyTestEntityCallbackExit, ...genericVisitors } = visitors;
return {
callExpressionListeners: {
enter: {
nonMocha: nonMochaCallExpression,
generic: genericVisitors.CallExpression
},
exit: {
nonMocha: nonMochaCallExpressionExit,
generic: genericVisitors['CallExpression:exit']
}
},
memberExpressionListeners: {
enter: {
mocha: mochaMemberExpression,
nonMocha: nonMochaMemberExpression,
generic: genericVisitors.MemberExpression
},
exit: {
mocha: mochaMemberExpressionExit,
nonMocha: nonMochaMemberExpressionExit,
generic: genericVisitors['MemberExpression:exit']
}
},
functionExpressionListeners: {
enter: {
mocha: mochaFunctionExpression,
nonMocha: nonMochaFunctionExpression,
generic: genericVisitors.FunctionExpression
},
exit: {
mocha: mochaFunctionExpressionExit,
nonMocha: nonMochaFunctionExpressionExit,
generic: genericVisitors['FunctionExpression:exit']
}
},
enterDispatchers: {
config,
testCase,
testCaseCallback,
suite,
suiteCallback,
hook,
hookCallback,
suiteOrTestCase,
anyTestEntity,
anyTestEntityCallback
},
exitDispatchers: {
config: configExit,
testCase: testCaseExit,
testCaseCallback: testCaseCallbackExit,
suite: suiteExit,
suiteCallback: suiteCallbackExit,
hook: hookExit,
hookCallback: hookCallbackExit,
suiteOrTestCase: suiteOrTestCaseExit,
anyTestEntity: anyTestEntityExit,
anyTestEntityCallback: anyTestEntityCallbackExit
},
genericVisitors
};
}
function createCallExpressionRuleListener(cachedMochaCallsByNode, listenerSet) {
if (listenerSet.mocha === undefined && listenerSet.nonMocha === undefined && listenerSet.generic === undefined) {
return undefined;
}
return function (node) {
callExpressionVisitor(cachedMochaCallsByNode, node, listenerSet);
};
}
function createExpressionRuleListener(cachedMochaCallsByNode, listenerSet) {
if (listenerSet.mocha === undefined && listenerSet.nonMocha === undefined && listenerSet.generic === undefined) {
return undefined;
}
return function (node) {
expressionVisitor(cachedMochaCallsByNode, node, listenerSet);
};
}
function createSpecificVisitors(cachedMochaCallsByNode, visitors) {
const callExpressionEnterListener = createCallExpressionRuleListener(cachedMochaCallsByNode, {
...visitors.callExpressionListeners.enter,
mocha: createCallExpressionDispatcher(visitors.enterDispatchers)
});
const callExpressionExitListener = createCallExpressionRuleListener(cachedMochaCallsByNode, {
...visitors.callExpressionListeners.exit,
mocha: createCallExpressionDispatcher(visitors.exitDispatchers)
});
const memberExpressionEnterListener = createExpressionRuleListener(cachedMochaCallsByNode, visitors.memberExpressionListeners.enter);
const memberExpressionExitListener = createExpressionRuleListener(cachedMochaCallsByNode, visitors.memberExpressionListeners.exit);
const functionExpressionEnterListener = createExpressionRuleListener(cachedMochaCallsByNode, visitors.functionExpressionListeners.enter);
const functionExpressionExitListener = createExpressionRuleListener(cachedMochaCallsByNode, visitors.functionExpressionListeners.exit);
return {
...createListenerRecord('CallExpression', callExpressionEnterListener),
...createListenerRecord('CallExpression:exit', callExpressionExitListener),
...createListenerRecord('MemberExpression', memberExpressionEnterListener),
...createListenerRecord('MemberExpression:exit', memberExpressionExitListener),
...createListenerRecord('FunctionExpression', functionExpressionEnterListener),
...createListenerRecord('FunctionExpression:exit', functionExpressionExitListener)
};
}
export function createMochaVisitors(context, visitors, options = {}) {
const splitVisitors = splitMochaVisitors(visitors);
const cachedMochaCallsByNode = findCallsCached(context, options);
return {
...splitVisitors.genericVisitors,
...createSpecificVisitors(cachedMochaCallsByNode, splitVisitors)
};
}
//# sourceMappingURL=mocha-visitors.js.map