项目原始demo,不改动
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
Den här utvecklingskatalogen är arkiverad. Du kan se filer och klona katalogen, men inte öppna ärenden eller genomföra push- eller pull-förfrågningar.

no-cond-assign.js 4.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /**
  2. * @fileoverview Rule to flag assignment in a conditional statement's test expression
  3. * @author Stephen Murray <spmurrayzzz>
  4. */
  5. "use strict";
  6. const astUtils = require("../ast-utils");
  7. const NODE_DESCRIPTIONS = {
  8. DoWhileStatement: "a 'do...while' statement",
  9. ForStatement: "a 'for' statement",
  10. IfStatement: "an 'if' statement",
  11. WhileStatement: "a 'while' statement"
  12. };
  13. //------------------------------------------------------------------------------
  14. // Rule Definition
  15. //------------------------------------------------------------------------------
  16. module.exports = {
  17. meta: {
  18. docs: {
  19. description: "disallow assignment operators in conditional expressions",
  20. category: "Possible Errors",
  21. recommended: true,
  22. url: "https://eslint.org/docs/rules/no-cond-assign"
  23. },
  24. schema: [
  25. {
  26. enum: ["except-parens", "always"]
  27. }
  28. ],
  29. messages: {
  30. unexpected: "Unexpected assignment within {{type}}.",
  31. // must match JSHint's error message
  32. missing: "Expected a conditional expression and instead saw an assignment."
  33. }
  34. },
  35. create(context) {
  36. const prohibitAssign = (context.options[0] || "except-parens");
  37. const sourceCode = context.getSourceCode();
  38. /**
  39. * Check whether an AST node is the test expression for a conditional statement.
  40. * @param {!Object} node The node to test.
  41. * @returns {boolean} `true` if the node is the text expression for a conditional statement; otherwise, `false`.
  42. */
  43. function isConditionalTestExpression(node) {
  44. return node.parent &&
  45. node.parent.test &&
  46. node === node.parent.test;
  47. }
  48. /**
  49. * Given an AST node, perform a bottom-up search for the first ancestor that represents a conditional statement.
  50. * @param {!Object} node The node to use at the start of the search.
  51. * @returns {?Object} The closest ancestor node that represents a conditional statement.
  52. */
  53. function findConditionalAncestor(node) {
  54. let currentAncestor = node;
  55. do {
  56. if (isConditionalTestExpression(currentAncestor)) {
  57. return currentAncestor.parent;
  58. }
  59. } while ((currentAncestor = currentAncestor.parent) && !astUtils.isFunction(currentAncestor));
  60. return null;
  61. }
  62. /**
  63. * Check whether the code represented by an AST node is enclosed in two sets of parentheses.
  64. * @param {!Object} node The node to test.
  65. * @returns {boolean} `true` if the code is enclosed in two sets of parentheses; otherwise, `false`.
  66. */
  67. function isParenthesisedTwice(node) {
  68. const previousToken = sourceCode.getTokenBefore(node, 1),
  69. nextToken = sourceCode.getTokenAfter(node, 1);
  70. return astUtils.isParenthesised(sourceCode, node) &&
  71. astUtils.isOpeningParenToken(previousToken) && previousToken.range[1] <= node.range[0] &&
  72. astUtils.isClosingParenToken(nextToken) && nextToken.range[0] >= node.range[1];
  73. }
  74. /**
  75. * Check a conditional statement's test expression for top-level assignments that are not enclosed in parentheses.
  76. * @param {!Object} node The node for the conditional statement.
  77. * @returns {void}
  78. */
  79. function testForAssign(node) {
  80. if (node.test &&
  81. (node.test.type === "AssignmentExpression") &&
  82. (node.type === "ForStatement"
  83. ? !astUtils.isParenthesised(sourceCode, node.test)
  84. : !isParenthesisedTwice(node.test)
  85. )
  86. ) {
  87. context.report({
  88. node,
  89. loc: node.test.loc.start,
  90. messageId: "missing"
  91. });
  92. }
  93. }
  94. /**
  95. * Check whether an assignment expression is descended from a conditional statement's test expression.
  96. * @param {!Object} node The node for the assignment expression.
  97. * @returns {void}
  98. */
  99. function testForConditionalAncestor(node) {
  100. const ancestor = findConditionalAncestor(node);
  101. if (ancestor) {
  102. context.report({
  103. node: ancestor,
  104. messageId: "unexpected",
  105. data: {
  106. type: NODE_DESCRIPTIONS[ancestor.type] || ancestor.type
  107. }
  108. });
  109. }
  110. }
  111. if (prohibitAssign === "always") {
  112. return {
  113. AssignmentExpression: testForConditionalAncestor
  114. };
  115. }
  116. return {
  117. DoWhileStatement: testForAssign,
  118. ForStatement: testForAssign,
  119. IfStatement: testForAssign,
  120. WhileStatement: testForAssign
  121. };
  122. }
  123. };