项目原始demo,不改动
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
Bu depo arşivlendi. Dosyaları görüntüleyebilir ve klonlayabilirsiniz ama işlem gönderemez ve konu/değişiklik isteği açamazsınız.
 
 
 
 

215 satır
7.4 KiB

  1. /**
  2. * @fileoverview Rule to flag use constant conditions
  3. * @author Christian Schulz <http://rndm.de>
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. module.exports = {
  10. meta: {
  11. docs: {
  12. description: "disallow constant expressions in conditions",
  13. category: "Possible Errors",
  14. recommended: true,
  15. url: "https://eslint.org/docs/rules/no-constant-condition"
  16. },
  17. schema: [
  18. {
  19. type: "object",
  20. properties: {
  21. checkLoops: {
  22. type: "boolean"
  23. }
  24. },
  25. additionalProperties: false
  26. }
  27. ],
  28. messages: {
  29. unexpected: "Unexpected constant condition."
  30. }
  31. },
  32. create(context) {
  33. const options = context.options[0] || {},
  34. checkLoops = options.checkLoops !== false,
  35. loopSetStack = [];
  36. let loopsInCurrentScope = new Set();
  37. //--------------------------------------------------------------------------
  38. // Helpers
  39. //--------------------------------------------------------------------------
  40. /**
  41. * Checks if a branch node of LogicalExpression short circuits the whole condition
  42. * @param {ASTNode} node The branch of main condition which needs to be checked
  43. * @param {string} operator The operator of the main LogicalExpression.
  44. * @returns {boolean} true when condition short circuits whole condition
  45. */
  46. function isLogicalIdentity(node, operator) {
  47. switch (node.type) {
  48. case "Literal":
  49. return (operator === "||" && node.value === true) ||
  50. (operator === "&&" && node.value === false);
  51. case "UnaryExpression":
  52. return (operator === "&&" && node.operator === "void");
  53. case "LogicalExpression":
  54. return isLogicalIdentity(node.left, node.operator) ||
  55. isLogicalIdentity(node.right, node.operator);
  56. // no default
  57. }
  58. return false;
  59. }
  60. /**
  61. * Checks if a node has a constant truthiness value.
  62. * @param {ASTNode} node The AST node to check.
  63. * @param {boolean} inBooleanPosition `false` if checking branch of a condition.
  64. * `true` in all other cases
  65. * @returns {Bool} true when node's truthiness is constant
  66. * @private
  67. */
  68. function isConstant(node, inBooleanPosition) {
  69. switch (node.type) {
  70. case "Literal":
  71. case "ArrowFunctionExpression":
  72. case "FunctionExpression":
  73. case "ObjectExpression":
  74. case "ArrayExpression":
  75. return true;
  76. case "UnaryExpression":
  77. if (node.operator === "void") {
  78. return true;
  79. }
  80. return (node.operator === "typeof" && inBooleanPosition) ||
  81. isConstant(node.argument, true);
  82. case "BinaryExpression":
  83. return isConstant(node.left, false) &&
  84. isConstant(node.right, false) &&
  85. node.operator !== "in";
  86. case "LogicalExpression": {
  87. const isLeftConstant = isConstant(node.left, inBooleanPosition);
  88. const isRightConstant = isConstant(node.right, inBooleanPosition);
  89. const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
  90. const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator));
  91. return (isLeftConstant && isRightConstant) || isLeftShortCircuit || isRightShortCircuit;
  92. }
  93. case "AssignmentExpression":
  94. return (node.operator === "=") && isConstant(node.right, inBooleanPosition);
  95. case "SequenceExpression":
  96. return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition);
  97. // no default
  98. }
  99. return false;
  100. }
  101. /**
  102. * Tracks when the given node contains a constant condition.
  103. * @param {ASTNode} node The AST node to check.
  104. * @returns {void}
  105. * @private
  106. */
  107. function trackConstantConditionLoop(node) {
  108. if (node.test && isConstant(node.test, true)) {
  109. loopsInCurrentScope.add(node);
  110. }
  111. }
  112. /**
  113. * Reports when the set contains the given constant condition node
  114. * @param {ASTNode} node The AST node to check.
  115. * @returns {void}
  116. * @private
  117. */
  118. function checkConstantConditionLoopInSet(node) {
  119. if (loopsInCurrentScope.has(node)) {
  120. loopsInCurrentScope.delete(node);
  121. context.report({ node: node.test, messageId: "unexpected" });
  122. }
  123. }
  124. /**
  125. * Reports when the given node contains a constant condition.
  126. * @param {ASTNode} node The AST node to check.
  127. * @returns {void}
  128. * @private
  129. */
  130. function reportIfConstant(node) {
  131. if (node.test && isConstant(node.test, true)) {
  132. context.report({ node: node.test, messageId: "unexpected" });
  133. }
  134. }
  135. /**
  136. * Stores current set of constant loops in loopSetStack temporarily
  137. * and uses a new set to track constant loops
  138. * @returns {void}
  139. * @private
  140. */
  141. function enterFunction() {
  142. loopSetStack.push(loopsInCurrentScope);
  143. loopsInCurrentScope = new Set();
  144. }
  145. /**
  146. * Reports when the set still contains stored constant conditions
  147. * @param {ASTNode} node The AST node to check.
  148. * @returns {void}
  149. * @private
  150. */
  151. function exitFunction() {
  152. loopsInCurrentScope = loopSetStack.pop();
  153. }
  154. /**
  155. * Checks node when checkLoops option is enabled
  156. * @param {ASTNode} node The AST node to check.
  157. * @returns {void}
  158. * @private
  159. */
  160. function checkLoop(node) {
  161. if (checkLoops) {
  162. trackConstantConditionLoop(node);
  163. }
  164. }
  165. //--------------------------------------------------------------------------
  166. // Public
  167. //--------------------------------------------------------------------------
  168. return {
  169. ConditionalExpression: reportIfConstant,
  170. IfStatement: reportIfConstant,
  171. WhileStatement: checkLoop,
  172. "WhileStatement:exit": checkConstantConditionLoopInSet,
  173. DoWhileStatement: checkLoop,
  174. "DoWhileStatement:exit": checkConstantConditionLoopInSet,
  175. ForStatement: checkLoop,
  176. "ForStatement > .test": node => checkLoop(node.parent),
  177. "ForStatement:exit": checkConstantConditionLoopInSet,
  178. FunctionDeclaration: enterFunction,
  179. "FunctionDeclaration:exit": exitFunction,
  180. YieldExpression: () => loopsInCurrentScope.clear()
  181. };
  182. }
  183. };