Blame view
node_modules/eslint/lib/rules/no-extra-bind.js
4.57 KB
f7563de62
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
/** * @fileoverview Rule to flag unnecessary bind calls * @author Bence Dányi <bence@danyi.me> */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: "disallow unnecessary calls to `.bind()`", category: "Best Practices", recommended: false }, schema: [], fixable: "code" }, create(context) { let scopeInfo = null; /** * Reports a given function node. * * @param {ASTNode} node - A node to report. This is a FunctionExpression or * an ArrowFunctionExpression. * @returns {void} */ function report(node) { context.report({ node: node.parent.parent, message: "The function binding is unnecessary.", loc: node.parent.property.loc.start, fix(fixer) { const firstTokenToRemove = context.getSourceCode() .getFirstTokenBetween(node.parent.object, node.parent.property, astUtils.isNotClosingParenToken); return fixer.removeRange([firstTokenToRemove.range[0], node.parent.parent.range[1]]); } }); } /** * Checks whether or not a given function node is the callee of `.bind()` * method. * * e.g. `(function() {}.bind(foo))` * * @param {ASTNode} node - A node to report. This is a FunctionExpression or * an ArrowFunctionExpression. * @returns {boolean} `true` if the node is the callee of `.bind()` method. */ function isCalleeOfBindMethod(node) { const parent = node.parent; const grandparent = parent.parent; return ( grandparent && grandparent.type === "CallExpression" && grandparent.callee === parent && grandparent.arguments.length === 1 && parent.type === "MemberExpression" && parent.object === node && astUtils.getStaticPropertyName(parent) === "bind" ); } /** * Adds a scope information object to the stack. * * @param {ASTNode} node - A node to add. This node is a FunctionExpression * or a FunctionDeclaration node. * @returns {void} */ function enterFunction(node) { scopeInfo = { isBound: isCalleeOfBindMethod(node), thisFound: false, upper: scopeInfo }; } /** * Removes the scope information object from the top of the stack. * At the same time, this reports the function node if the function has * `.bind()` and the `this` keywords found. * * @param {ASTNode} node - A node to remove. This node is a * FunctionExpression or a FunctionDeclaration node. * @returns {void} */ function exitFunction(node) { if (scopeInfo.isBound && !scopeInfo.thisFound) { report(node); } scopeInfo = scopeInfo.upper; } /** * Reports a given arrow function if the function is callee of `.bind()` * method. * * @param {ASTNode} node - A node to report. This node is an * ArrowFunctionExpression. * @returns {void} */ function exitArrowFunction(node) { if (isCalleeOfBindMethod(node)) { report(node); } } /** * Set the mark as the `this` keyword was found in this scope. * * @returns {void} */ function markAsThisFound() { if (scopeInfo) { scopeInfo.thisFound = true; } } return { "ArrowFunctionExpression:exit": exitArrowFunction, FunctionDeclaration: enterFunction, "FunctionDeclaration:exit": exitFunction, FunctionExpression: enterFunction, "FunctionExpression:exit": exitFunction, ThisExpression: markAsThisFound }; } }; |