Ohm-Management - Projektarbeit B-ME
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.

consistent-return.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /**
  2. * @fileoverview Rule to flag consistent return values
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const lodash = require("lodash");
  10. const astUtils = require("../util/ast-utils");
  11. //------------------------------------------------------------------------------
  12. // Helpers
  13. //------------------------------------------------------------------------------
  14. /**
  15. * Checks whether or not a given node is an `Identifier` node which was named a given name.
  16. * @param {ASTNode} node - A node to check.
  17. * @param {string} name - An expected name of the node.
  18. * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected.
  19. */
  20. function isIdentifier(node, name) {
  21. return node.type === "Identifier" && node.name === name;
  22. }
  23. /**
  24. * Checks whether or not a given code path segment is unreachable.
  25. * @param {CodePathSegment} segment - A CodePathSegment to check.
  26. * @returns {boolean} `true` if the segment is unreachable.
  27. */
  28. function isUnreachable(segment) {
  29. return !segment.reachable;
  30. }
  31. /**
  32. * Checks whether a given node is a `constructor` method in an ES6 class
  33. * @param {ASTNode} node A node to check
  34. * @returns {boolean} `true` if the node is a `constructor` method
  35. */
  36. function isClassConstructor(node) {
  37. return node.type === "FunctionExpression" &&
  38. node.parent &&
  39. node.parent.type === "MethodDefinition" &&
  40. node.parent.kind === "constructor";
  41. }
  42. //------------------------------------------------------------------------------
  43. // Rule Definition
  44. //------------------------------------------------------------------------------
  45. module.exports = {
  46. meta: {
  47. type: "suggestion",
  48. docs: {
  49. description: "require `return` statements to either always or never specify values",
  50. category: "Best Practices",
  51. recommended: false,
  52. url: "https://eslint.org/docs/rules/consistent-return"
  53. },
  54. schema: [{
  55. type: "object",
  56. properties: {
  57. treatUndefinedAsUnspecified: {
  58. type: "boolean"
  59. }
  60. },
  61. additionalProperties: false
  62. }],
  63. messages: {
  64. missingReturn: "Expected to return a value at the end of {{name}}.",
  65. missingReturnValue: "{{name}} expected a return value.",
  66. unexpectedReturnValue: "{{name}} expected no return value."
  67. }
  68. },
  69. create(context) {
  70. const options = context.options[0] || {};
  71. const treatUndefinedAsUnspecified = options.treatUndefinedAsUnspecified === true;
  72. let funcInfo = null;
  73. /**
  74. * Checks whether of not the implicit returning is consistent if the last
  75. * code path segment is reachable.
  76. *
  77. * @param {ASTNode} node - A program/function node to check.
  78. * @returns {void}
  79. */
  80. function checkLastSegment(node) {
  81. let loc, name;
  82. /*
  83. * Skip if it expected no return value or unreachable.
  84. * When unreachable, all paths are returned or thrown.
  85. */
  86. if (!funcInfo.hasReturnValue ||
  87. funcInfo.codePath.currentSegments.every(isUnreachable) ||
  88. astUtils.isES5Constructor(node) ||
  89. isClassConstructor(node)
  90. ) {
  91. return;
  92. }
  93. // Adjust a location and a message.
  94. if (node.type === "Program") {
  95. // The head of program.
  96. loc = { line: 1, column: 0 };
  97. name = "program";
  98. } else if (node.type === "ArrowFunctionExpression") {
  99. // `=>` token
  100. loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc.start;
  101. } else if (
  102. node.parent.type === "MethodDefinition" ||
  103. (node.parent.type === "Property" && node.parent.method)
  104. ) {
  105. // Method name.
  106. loc = node.parent.key.loc.start;
  107. } else {
  108. // Function name or `function` keyword.
  109. loc = (node.id || node).loc.start;
  110. }
  111. if (!name) {
  112. name = astUtils.getFunctionNameWithKind(node);
  113. }
  114. // Reports.
  115. context.report({
  116. node,
  117. loc,
  118. messageId: "missingReturn",
  119. data: { name }
  120. });
  121. }
  122. return {
  123. // Initializes/Disposes state of each code path.
  124. onCodePathStart(codePath, node) {
  125. funcInfo = {
  126. upper: funcInfo,
  127. codePath,
  128. hasReturn: false,
  129. hasReturnValue: false,
  130. messageId: "",
  131. node
  132. };
  133. },
  134. onCodePathEnd() {
  135. funcInfo = funcInfo.upper;
  136. },
  137. // Reports a given return statement if it's inconsistent.
  138. ReturnStatement(node) {
  139. const argument = node.argument;
  140. let hasReturnValue = Boolean(argument);
  141. if (treatUndefinedAsUnspecified && hasReturnValue) {
  142. hasReturnValue = !isIdentifier(argument, "undefined") && argument.operator !== "void";
  143. }
  144. if (!funcInfo.hasReturn) {
  145. funcInfo.hasReturn = true;
  146. funcInfo.hasReturnValue = hasReturnValue;
  147. funcInfo.messageId = hasReturnValue ? "missingReturnValue" : "unexpectedReturnValue";
  148. funcInfo.data = {
  149. name: funcInfo.node.type === "Program"
  150. ? "Program"
  151. : lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
  152. };
  153. } else if (funcInfo.hasReturnValue !== hasReturnValue) {
  154. context.report({
  155. node,
  156. messageId: funcInfo.messageId,
  157. data: funcInfo.data
  158. });
  159. }
  160. },
  161. // Reports a given program/function if the implicit returning is not consistent.
  162. "Program:exit": checkLastSegment,
  163. "FunctionDeclaration:exit": checkLastSegment,
  164. "FunctionExpression:exit": checkLastSegment,
  165. "ArrowFunctionExpression:exit": checkLastSegment
  166. };
  167. }
  168. };