UNPKG

eslint-plugin-jest

Version:
218 lines (174 loc) 7.2 kB
'use strict'; const path = require('path'); const _require = require('../../package.json'), version = _require.version; const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest'; const expectCase = node => node.callee.name === 'expect' && node.arguments.length === 1 && node.parent && node.parent.type === 'MemberExpression' && node.parent.parent; const expectNotCase = node => expectCase(node) && node.parent.parent.type === 'MemberExpression' && methodName(node) === 'not'; const expectResolveCase = node => expectCase(node) && node.parent.parent.type === 'MemberExpression' && methodName(node) === 'resolve'; const expectRejectCase = node => expectCase(node) && node.parent.parent.type === 'MemberExpression' && methodName(node) === 'reject'; const expectToBeCase = (node, arg) => !(expectNotCase(node) || expectResolveCase(node) || expectRejectCase(node)) && expectCase(node) && methodName(node) === 'toBe' && argument(node) && (argument(node).type === 'Literal' && argument(node).value === null && arg === null || argument(node).name === 'undefined' && arg === undefined); const expectNotToBeCase = (node, arg) => expectNotCase(node) && methodName2(node) === 'toBe' && argument2(node) && (argument2(node).type === 'Literal' && argument2(node).value === null && arg === null || argument2(node).name === 'undefined' && arg === undefined); const expectToEqualCase = (node, arg) => !(expectNotCase(node) || expectResolveCase(node) || expectRejectCase(node)) && expectCase(node) && methodName(node) === 'toEqual' && argument(node) && (argument(node).type === 'Literal' && argument(node).value === null && arg === null || argument(node).name === 'undefined' && arg === undefined); const expectNotToEqualCase = (node, arg) => expectNotCase(node) && methodName2(node) === 'toEqual' && argument2(node) && (argument2(node).type === 'Literal' && argument2(node).value === null && arg === null || argument2(node).name === 'undefined' && arg === undefined); const method = node => node.parent.property; const method2 = node => node.parent.parent.property; const methodName = node => method(node).name; const methodName2 = node => method2(node).name; const argument = node => node.parent.parent.arguments && node.parent.parent.arguments[0]; const argument2 = node => node.parent.parent.parent.arguments && node.parent.parent.parent.arguments[0]; const describeAliases = Object.assign(Object.create(null), { describe: true, 'describe.only': true, 'describe.skip': true, fdescribe: true, xdescribe: true }); const testCaseNames = Object.assign(Object.create(null), { fit: true, it: true, 'it.only': true, 'it.skip': true, test: true, 'test.only': true, 'test.skip': true, xit: true, xtest: true }); const getNodeName = node => { function joinNames(a, b) { return a && b ? `${a}.${b}` : null; } switch (node && node.type) { case 'Identifier': return node.name; case 'Literal': return node.value; case 'TemplateLiteral': if (node.expressions.length === 0) return node.quasis[0].value.cooked; break; case 'MemberExpression': return joinNames(getNodeName(node.object), getNodeName(node.property)); } return null; }; const isTestCase = node => node && node.type === 'CallExpression' && testCaseNames[getNodeName(node.callee)]; const isDescribe = node => node.type === 'CallExpression' && describeAliases[getNodeName(node.callee)]; const isFunction = node => node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression'; const isString = node => node.type === 'Literal' && typeof node.value === 'string' || isTemplateLiteral(node); const isTemplateLiteral = node => node.type === 'TemplateLiteral'; const hasExpressions = node => node.expressions && node.expressions.length > 0; const getStringValue = arg => isTemplateLiteral(arg) ? arg.quasis[0].value.raw : arg.value; /** * Generates the URL to documentation for the given rule name. It uses the * package version to build the link to a tagged version of the * documentation file. * * @param {string} filename - Name of the eslint rule * @returns {string} URL to the documentation for the given rule */ const getDocsUrl = filename => { const ruleName = path.basename(filename, '.js'); return `${REPO_URL}/blob/v${version}/docs/rules/${ruleName}.md`; }; const collectReferences = scope => { const locals = new Set(); const unresolved = new Set(); let currentScope = scope; while (currentScope !== null) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = currentScope.variables[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { const ref = _step.value; const isReferenceDefined = ref.defs.some(def => { return def.type !== 'ImplicitGlobalVariable'; }); if (isReferenceDefined) { locals.add(ref.name); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = currentScope.through[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { const ref = _step2.value; unresolved.add(ref.identifier.name); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return != null) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } currentScope = currentScope.upper; } return { locals, unresolved }; }; const scopeHasLocalReference = (scope, referenceName) => { const references = collectReferences(scope); return (// referenceName was found as a local variable or function declaration. references.locals.has(referenceName) || // referenceName was not found as an unresolved reference, // meaning it is likely not an implicit global reference. !references.unresolved.has(referenceName) ); }; function composeFixers(node) { return (...fixers) => { return fixerApi => { return fixers.reduce((all, fixer) => [...all, fixer(node, fixerApi)], []); }; }; } module.exports = { method, method2, argument, argument2, expectCase, expectNotCase, expectResolveCase, expectRejectCase, expectToBeCase, expectNotToBeCase, expectToEqualCase, expectNotToEqualCase, getNodeName, getStringValue, isDescribe, isFunction, isTemplateLiteral, isTestCase, isString, hasExpressions, getDocsUrl, scopeHasLocalReference, composeFixers };