项目原始demo,不改动
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
Este repositório está arquivado. Pode ver ficheiros e cloná-lo, mas não pode fazer envios ou lançar questões ou pedidos de integração.
 
 
 
 

218 linhas
6.4 KiB

  1. /**
  2. * @fileoverview Rule to disallow assignments where both sides are exactly the same
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("../ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Helpers
  12. //------------------------------------------------------------------------------
  13. const SPACES = /\s+/g;
  14. /**
  15. * Checks whether the property of 2 given member expression nodes are the same
  16. * property or not.
  17. *
  18. * @param {ASTNode} left - A member expression node to check.
  19. * @param {ASTNode} right - Another member expression node to check.
  20. * @returns {boolean} `true` if the member expressions have the same property.
  21. */
  22. function isSameProperty(left, right) {
  23. if (left.property.type === "Identifier" &&
  24. left.property.type === right.property.type &&
  25. left.property.name === right.property.name &&
  26. left.computed === right.computed
  27. ) {
  28. return true;
  29. }
  30. const lname = astUtils.getStaticPropertyName(left);
  31. const rname = astUtils.getStaticPropertyName(right);
  32. return lname !== null && lname === rname;
  33. }
  34. /**
  35. * Checks whether 2 given member expression nodes are the reference to the same
  36. * property or not.
  37. *
  38. * @param {ASTNode} left - A member expression node to check.
  39. * @param {ASTNode} right - Another member expression node to check.
  40. * @returns {boolean} `true` if the member expressions are the reference to the
  41. * same property or not.
  42. */
  43. function isSameMember(left, right) {
  44. if (!isSameProperty(left, right)) {
  45. return false;
  46. }
  47. const lobj = left.object;
  48. const robj = right.object;
  49. if (lobj.type !== robj.type) {
  50. return false;
  51. }
  52. if (lobj.type === "MemberExpression") {
  53. return isSameMember(lobj, robj);
  54. }
  55. return lobj.type === "Identifier" && lobj.name === robj.name;
  56. }
  57. /**
  58. * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
  59. *
  60. * @param {ASTNode|null} left - A left node to traverse. This is a Pattern or
  61. * a Property.
  62. * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or
  63. * a Property.
  64. * @param {boolean} props - The flag to check member expressions as well.
  65. * @param {Function} report - A callback function to report.
  66. * @returns {void}
  67. */
  68. function eachSelfAssignment(left, right, props, report) {
  69. if (!left || !right) {
  70. // do nothing
  71. } else if (
  72. left.type === "Identifier" &&
  73. right.type === "Identifier" &&
  74. left.name === right.name
  75. ) {
  76. report(right);
  77. } else if (
  78. left.type === "ArrayPattern" &&
  79. right.type === "ArrayExpression"
  80. ) {
  81. const end = Math.min(left.elements.length, right.elements.length);
  82. for (let i = 0; i < end; ++i) {
  83. const rightElement = right.elements[i];
  84. eachSelfAssignment(left.elements[i], rightElement, props, report);
  85. // After a spread element, those indices are unknown.
  86. if (rightElement && rightElement.type === "SpreadElement") {
  87. break;
  88. }
  89. }
  90. } else if (
  91. left.type === "RestElement" &&
  92. right.type === "SpreadElement"
  93. ) {
  94. eachSelfAssignment(left.argument, right.argument, props, report);
  95. } else if (
  96. left.type === "ObjectPattern" &&
  97. right.type === "ObjectExpression" &&
  98. right.properties.length >= 1
  99. ) {
  100. /*
  101. * Gets the index of the last spread property.
  102. * It's possible to overwrite properties followed by it.
  103. */
  104. let startJ = 0;
  105. for (let i = right.properties.length - 1; i >= 0; --i) {
  106. const propType = right.properties[i].type;
  107. if (propType === "SpreadElement" || propType === "ExperimentalSpreadProperty") {
  108. startJ = i + 1;
  109. break;
  110. }
  111. }
  112. for (let i = 0; i < left.properties.length; ++i) {
  113. for (let j = startJ; j < right.properties.length; ++j) {
  114. eachSelfAssignment(
  115. left.properties[i],
  116. right.properties[j],
  117. props,
  118. report
  119. );
  120. }
  121. }
  122. } else if (
  123. left.type === "Property" &&
  124. right.type === "Property" &&
  125. !left.computed &&
  126. !right.computed &&
  127. right.kind === "init" &&
  128. !right.method &&
  129. left.key.name === right.key.name
  130. ) {
  131. eachSelfAssignment(left.value, right.value, props, report);
  132. } else if (
  133. props &&
  134. left.type === "MemberExpression" &&
  135. right.type === "MemberExpression" &&
  136. isSameMember(left, right)
  137. ) {
  138. report(right);
  139. }
  140. }
  141. //------------------------------------------------------------------------------
  142. // Rule Definition
  143. //------------------------------------------------------------------------------
  144. module.exports = {
  145. meta: {
  146. docs: {
  147. description: "disallow assignments where both sides are exactly the same",
  148. category: "Best Practices",
  149. recommended: true,
  150. url: "https://eslint.org/docs/rules/no-self-assign"
  151. },
  152. schema: [
  153. {
  154. type: "object",
  155. properties: {
  156. props: {
  157. type: "boolean"
  158. }
  159. },
  160. additionalProperties: false
  161. }
  162. ]
  163. },
  164. create(context) {
  165. const sourceCode = context.getSourceCode();
  166. const options = context.options[0];
  167. const props = Boolean(options && options.props);
  168. /**
  169. * Reports a given node as self assignments.
  170. *
  171. * @param {ASTNode} node - A node to report. This is an Identifier node.
  172. * @returns {void}
  173. */
  174. function report(node) {
  175. context.report({
  176. node,
  177. message: "'{{name}}' is assigned to itself.",
  178. data: {
  179. name: sourceCode.getText(node).replace(SPACES, "")
  180. }
  181. });
  182. }
  183. return {
  184. AssignmentExpression(node) {
  185. if (node.operator === "=") {
  186. eachSelfAssignment(node.left, node.right, props, report);
  187. }
  188. }
  189. };
  190. }
  191. };