UNPKG

react-carousel-query

Version:

A infinite carousel component made with react that handles the pagination for you.

186 lines (165 loc) 6.56 kB
/** * @author Jamund Ferguson * See LICENSE file in root directory for full license. */ "use strict" module.exports = { meta: { type: "suggestion", docs: { description: "require `return` statements after callbacks", category: "Stylistic Issues", recommended: false, url: "https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md", }, schema: [ { type: "array", items: { type: "string" }, }, ], fixable: null, messages: { missingReturn: "Expected return with your callback function.", }, }, create(context) { const callbacks = context.options[0] || ["callback", "cb", "next"] const sourceCode = context.getSourceCode() /** * Find the closest parent matching a list of types. * @param {ASTNode} node The node whose parents we are searching * @param {Array} types The node types to match * @returns {ASTNode} The matched node or undefined. */ function findClosestParentOfType(node, types) { if (!node.parent) { return null } if (types.indexOf(node.parent.type) === -1) { return findClosestParentOfType(node.parent, types) } return node.parent } /** * Check to see if a node contains only identifers * @param {ASTNode} node The node to check * @returns {boolean} Whether or not the node contains only identifers */ function containsOnlyIdentifiers(node) { if (node.type === "Identifier") { return true } if (node.type === "MemberExpression") { if (node.object.type === "Identifier") { return true } if (node.object.type === "MemberExpression") { return containsOnlyIdentifiers(node.object) } } return false } /** * Check to see if a CallExpression is in our callback list. * @param {ASTNode} node The node to check against our callback names list. * @returns {boolean} Whether or not this function matches our callback name. */ function isCallback(node) { return ( containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1 ) } /** * Determines whether or not the callback is part of a callback expression. * @param {ASTNode} node The callback node * @param {ASTNode} parentNode The expression node * @returns {boolean} Whether or not this is part of a callback expression */ function isCallbackExpression(node, parentNode) { // ensure the parent node exists and is an expression if (!parentNode || parentNode.type !== "ExpressionStatement") { return false } // cb() if (parentNode.expression === node) { return true } // special case for cb && cb() and similar if ( parentNode.expression.type === "BinaryExpression" || parentNode.expression.type === "LogicalExpression" ) { if (parentNode.expression.right === node) { return true } } return false } return { CallExpression(node) { // if we're not a callback we can return if (!isCallback(node)) { return } // find the closest block, return or loop const closestBlock = findClosestParentOfType(node, [ "BlockStatement", "ReturnStatement", "ArrowFunctionExpression", ]) || {} // if our parent is a return we know we're ok if (closestBlock.type === "ReturnStatement") { return } // arrow functions don't always have blocks and implicitly return if (closestBlock.type === "ArrowFunctionExpression") { return } // block statements are part of functions and most if statements if (closestBlock.type === "BlockStatement") { // find the last item in the block const lastItem = closestBlock.body[closestBlock.body.length - 1] // if the callback is the last thing in a block that might be ok if (isCallbackExpression(node, lastItem)) { const parentType = closestBlock.parent.type // but only if the block is part of a function if ( parentType === "FunctionExpression" || parentType === "FunctionDeclaration" || parentType === "ArrowFunctionExpression" ) { return } } // ending a block with a return is also ok if (lastItem.type === "ReturnStatement") { // but only if the callback is immediately before if ( isCallbackExpression( node, closestBlock.body[closestBlock.body.length - 2] ) ) { return } } } // as long as you're the child of a function at this point you should be asked to return if ( findClosestParentOfType(node, [ "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", ]) ) { context.report({ node, messageId: "missingReturn" }) } }, } }, }