项目原始demo,不改动
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 

211 lines
6.7 KiB

  1. /**
  2. * @fileoverview Rule to disallow mixed binary operators.
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("../ast-utils.js");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. const ARITHMETIC_OPERATORS = ["+", "-", "*", "/", "%", "**"];
  14. const BITWISE_OPERATORS = ["&", "|", "^", "~", "<<", ">>", ">>>"];
  15. const COMPARISON_OPERATORS = ["==", "!=", "===", "!==", ">", ">=", "<", "<="];
  16. const LOGICAL_OPERATORS = ["&&", "||"];
  17. const RELATIONAL_OPERATORS = ["in", "instanceof"];
  18. const ALL_OPERATORS = [].concat(
  19. ARITHMETIC_OPERATORS,
  20. BITWISE_OPERATORS,
  21. COMPARISON_OPERATORS,
  22. LOGICAL_OPERATORS,
  23. RELATIONAL_OPERATORS
  24. );
  25. const DEFAULT_GROUPS = [
  26. ARITHMETIC_OPERATORS,
  27. BITWISE_OPERATORS,
  28. COMPARISON_OPERATORS,
  29. LOGICAL_OPERATORS,
  30. RELATIONAL_OPERATORS
  31. ];
  32. const TARGET_NODE_TYPE = /^(?:Binary|Logical)Expression$/;
  33. /**
  34. * Normalizes options.
  35. *
  36. * @param {Object|undefined} options - A options object to normalize.
  37. * @returns {Object} Normalized option object.
  38. */
  39. function normalizeOptions(options) {
  40. const hasGroups = (options && options.groups && options.groups.length > 0);
  41. const groups = hasGroups ? options.groups : DEFAULT_GROUPS;
  42. const allowSamePrecedence = (options && options.allowSamePrecedence) !== false;
  43. return {
  44. groups,
  45. allowSamePrecedence
  46. };
  47. }
  48. /**
  49. * Checks whether any group which includes both given operator exists or not.
  50. *
  51. * @param {Array.<string[]>} groups - A list of groups to check.
  52. * @param {string} left - An operator.
  53. * @param {string} right - Another operator.
  54. * @returns {boolean} `true` if such group existed.
  55. */
  56. function includesBothInAGroup(groups, left, right) {
  57. return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1);
  58. }
  59. //------------------------------------------------------------------------------
  60. // Rule Definition
  61. //------------------------------------------------------------------------------
  62. module.exports = {
  63. meta: {
  64. docs: {
  65. description: "disallow mixed binary operators",
  66. category: "Stylistic Issues",
  67. recommended: false,
  68. url: "https://eslint.org/docs/rules/no-mixed-operators"
  69. },
  70. schema: [
  71. {
  72. type: "object",
  73. properties: {
  74. groups: {
  75. type: "array",
  76. items: {
  77. type: "array",
  78. items: { enum: ALL_OPERATORS },
  79. minItems: 2,
  80. uniqueItems: true
  81. },
  82. uniqueItems: true
  83. },
  84. allowSamePrecedence: {
  85. type: "boolean"
  86. }
  87. },
  88. additionalProperties: false
  89. }
  90. ]
  91. },
  92. create(context) {
  93. const sourceCode = context.getSourceCode();
  94. const options = normalizeOptions(context.options[0]);
  95. /**
  96. * Checks whether a given node should be ignored by options or not.
  97. *
  98. * @param {ASTNode} node - A node to check. This is a BinaryExpression
  99. * node or a LogicalExpression node. This parent node is one of
  100. * them, too.
  101. * @returns {boolean} `true` if the node should be ignored.
  102. */
  103. function shouldIgnore(node) {
  104. const a = node;
  105. const b = node.parent;
  106. return (
  107. !includesBothInAGroup(options.groups, a.operator, b.operator) ||
  108. (
  109. options.allowSamePrecedence &&
  110. astUtils.getPrecedence(a) === astUtils.getPrecedence(b)
  111. )
  112. );
  113. }
  114. /**
  115. * Checks whether the operator of a given node is mixed with parent
  116. * node's operator or not.
  117. *
  118. * @param {ASTNode} node - A node to check. This is a BinaryExpression
  119. * node or a LogicalExpression node. This parent node is one of
  120. * them, too.
  121. * @returns {boolean} `true` if the node was mixed.
  122. */
  123. function isMixedWithParent(node) {
  124. return (
  125. node.operator !== node.parent.operator &&
  126. !astUtils.isParenthesised(sourceCode, node)
  127. );
  128. }
  129. /**
  130. * Gets the operator token of a given node.
  131. *
  132. * @param {ASTNode} node - A node to check. This is a BinaryExpression
  133. * node or a LogicalExpression node.
  134. * @returns {Token} The operator token of the node.
  135. */
  136. function getOperatorToken(node) {
  137. return sourceCode.getTokenAfter(node.left, astUtils.isNotClosingParenToken);
  138. }
  139. /**
  140. * Reports both the operator of a given node and the operator of the
  141. * parent node.
  142. *
  143. * @param {ASTNode} node - A node to check. This is a BinaryExpression
  144. * node or a LogicalExpression node. This parent node is one of
  145. * them, too.
  146. * @returns {void}
  147. */
  148. function reportBothOperators(node) {
  149. const parent = node.parent;
  150. const left = (parent.left === node) ? node : parent;
  151. const right = (parent.left !== node) ? node : parent;
  152. const message =
  153. "Unexpected mix of '{{leftOperator}}' and '{{rightOperator}}'.";
  154. const data = {
  155. leftOperator: left.operator,
  156. rightOperator: right.operator
  157. };
  158. context.report({
  159. node: left,
  160. loc: getOperatorToken(left).loc.start,
  161. message,
  162. data
  163. });
  164. context.report({
  165. node: right,
  166. loc: getOperatorToken(right).loc.start,
  167. message,
  168. data
  169. });
  170. }
  171. /**
  172. * Checks between the operator of this node and the operator of the
  173. * parent node.
  174. *
  175. * @param {ASTNode} node - A node to check.
  176. * @returns {void}
  177. */
  178. function check(node) {
  179. if (TARGET_NODE_TYPE.test(node.parent.type) &&
  180. isMixedWithParent(node) &&
  181. !shouldIgnore(node)
  182. ) {
  183. reportBothOperators(node);
  184. }
  185. }
  186. return {
  187. BinaryExpression: check,
  188. LogicalExpression: check
  189. };
  190. }
  191. };