Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

no-setter-return.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /**
  2. * @fileoverview Rule to disallow returning values from setters
  3. * @author Milos Djermanovic
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("./utils/ast-utils");
  10. const { findVariable } = require("eslint-utils");
  11. //------------------------------------------------------------------------------
  12. // Helpers
  13. //------------------------------------------------------------------------------
  14. /**
  15. * Determines whether the given identifier node is a reference to a global variable.
  16. * @param {ASTNode} node `Identifier` node to check.
  17. * @param {Scope} scope Scope to which the node belongs.
  18. * @returns {boolean} True if the identifier is a reference to a global variable.
  19. */
  20. function isGlobalReference(node, scope) {
  21. const variable = findVariable(scope, node);
  22. return variable !== null && variable.scope.type === "global" && variable.defs.length === 0;
  23. }
  24. /**
  25. * Determines whether the given node is an argument of the specified global method call, at the given `index` position.
  26. * E.g., for given `index === 1`, this function checks for `objectName.methodName(foo, node)`, where objectName is a global variable.
  27. * @param {ASTNode} node The node to check.
  28. * @param {Scope} scope Scope to which the node belongs.
  29. * @param {string} objectName Name of the global object.
  30. * @param {string} methodName Name of the method.
  31. * @param {number} index The given position.
  32. * @returns {boolean} `true` if the node is argument at the given position.
  33. */
  34. function isArgumentOfGlobalMethodCall(node, scope, objectName, methodName, index) {
  35. const callNode = node.parent;
  36. return callNode.type === "CallExpression" &&
  37. callNode.arguments[index] === node &&
  38. astUtils.isSpecificMemberAccess(callNode.callee, objectName, methodName) &&
  39. isGlobalReference(astUtils.skipChainExpression(callNode.callee).object, scope);
  40. }
  41. /**
  42. * Determines whether the given node is used as a property descriptor.
  43. * @param {ASTNode} node The node to check.
  44. * @param {Scope} scope Scope to which the node belongs.
  45. * @returns {boolean} `true` if the node is a property descriptor.
  46. */
  47. function isPropertyDescriptor(node, scope) {
  48. if (
  49. isArgumentOfGlobalMethodCall(node, scope, "Object", "defineProperty", 2) ||
  50. isArgumentOfGlobalMethodCall(node, scope, "Reflect", "defineProperty", 2)
  51. ) {
  52. return true;
  53. }
  54. const parent = node.parent;
  55. if (
  56. parent.type === "Property" &&
  57. parent.value === node
  58. ) {
  59. const grandparent = parent.parent;
  60. if (
  61. grandparent.type === "ObjectExpression" &&
  62. (
  63. isArgumentOfGlobalMethodCall(grandparent, scope, "Object", "create", 1) ||
  64. isArgumentOfGlobalMethodCall(grandparent, scope, "Object", "defineProperties", 1)
  65. )
  66. ) {
  67. return true;
  68. }
  69. }
  70. return false;
  71. }
  72. /**
  73. * Determines whether the given function node is used as a setter function.
  74. * @param {ASTNode} node The node to check.
  75. * @param {Scope} scope Scope to which the node belongs.
  76. * @returns {boolean} `true` if the node is a setter.
  77. */
  78. function isSetter(node, scope) {
  79. const parent = node.parent;
  80. if (
  81. parent.kind === "set" &&
  82. parent.value === node
  83. ) {
  84. // Setter in an object literal or in a class
  85. return true;
  86. }
  87. if (
  88. parent.type === "Property" &&
  89. parent.value === node &&
  90. astUtils.getStaticPropertyName(parent) === "set" &&
  91. parent.parent.type === "ObjectExpression" &&
  92. isPropertyDescriptor(parent.parent, scope)
  93. ) {
  94. // Setter in a property descriptor
  95. return true;
  96. }
  97. return false;
  98. }
  99. /**
  100. * Finds function's outer scope.
  101. * @param {Scope} scope Function's own scope.
  102. * @returns {Scope} Function's outer scope.
  103. */
  104. function getOuterScope(scope) {
  105. const upper = scope.upper;
  106. if (upper.type === "function-expression-name") {
  107. return upper.upper;
  108. }
  109. return upper;
  110. }
  111. //------------------------------------------------------------------------------
  112. // Rule Definition
  113. //------------------------------------------------------------------------------
  114. module.exports = {
  115. meta: {
  116. type: "problem",
  117. docs: {
  118. description: "disallow returning values from setters",
  119. category: "Possible Errors",
  120. recommended: true,
  121. url: "https://eslint.org/docs/rules/no-setter-return"
  122. },
  123. schema: [],
  124. messages: {
  125. returnsValue: "Setter cannot return a value."
  126. }
  127. },
  128. create(context) {
  129. let funcInfo = null;
  130. /**
  131. * Creates and pushes to the stack a function info object for the given function node.
  132. * @param {ASTNode} node The function node.
  133. * @returns {void}
  134. */
  135. function enterFunction(node) {
  136. const outerScope = getOuterScope(context.getScope());
  137. funcInfo = {
  138. upper: funcInfo,
  139. isSetter: isSetter(node, outerScope)
  140. };
  141. }
  142. /**
  143. * Pops the current function info object from the stack.
  144. * @returns {void}
  145. */
  146. function exitFunction() {
  147. funcInfo = funcInfo.upper;
  148. }
  149. /**
  150. * Reports the given node.
  151. * @param {ASTNode} node Node to report.
  152. * @returns {void}
  153. */
  154. function report(node) {
  155. context.report({ node, messageId: "returnsValue" });
  156. }
  157. return {
  158. /*
  159. * Function declarations cannot be setters, but we still have to track them in the `funcInfo` stack to avoid
  160. * false positives, because a ReturnStatement node can belong to a function declaration inside a setter.
  161. *
  162. * Note: A previously declared function can be referenced and actually used as a setter in a property descriptor,
  163. * but that's out of scope for this rule.
  164. */
  165. FunctionDeclaration: enterFunction,
  166. FunctionExpression: enterFunction,
  167. ArrowFunctionExpression(node) {
  168. enterFunction(node);
  169. if (funcInfo.isSetter && node.expression) {
  170. // { set: foo => bar } property descriptor. Report implicit return 'bar' as the equivalent for a return statement.
  171. report(node.body);
  172. }
  173. },
  174. "FunctionDeclaration:exit": exitFunction,
  175. "FunctionExpression:exit": exitFunction,
  176. "ArrowFunctionExpression:exit": exitFunction,
  177. ReturnStatement(node) {
  178. // Global returns (e.g., at the top level of a Node module) don't have `funcInfo`.
  179. if (funcInfo && funcInfo.isSetter && node.argument) {
  180. report(node);
  181. }
  182. }
  183. };
  184. }
  185. };