UNPKG

eslint-plugin-mocha

Version:

Eslint rules for mocha.

263 lines 11.7 kB
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