项目原始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.

prefer-destructuring.js 7.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * @fileoverview Prefer destructuring from arrays and objects
  3. * @author Alex LaFroscia
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. module.exports = {
  10. meta: {
  11. docs: {
  12. description: "require destructuring from arrays and/or objects",
  13. category: "ECMAScript 6",
  14. recommended: false,
  15. url: "https://eslint.org/docs/rules/prefer-destructuring"
  16. },
  17. schema: [
  18. {
  19. /*
  20. * old support {array: Boolean, object: Boolean}
  21. * new support {VariableDeclarator: {}, AssignmentExpression: {}}
  22. */
  23. oneOf: [
  24. {
  25. type: "object",
  26. properties: {
  27. VariableDeclarator: {
  28. type: "object",
  29. properties: {
  30. array: {
  31. type: "boolean"
  32. },
  33. object: {
  34. type: "boolean"
  35. }
  36. },
  37. additionalProperties: false
  38. },
  39. AssignmentExpression: {
  40. type: "object",
  41. properties: {
  42. array: {
  43. type: "boolean"
  44. },
  45. object: {
  46. type: "boolean"
  47. }
  48. },
  49. additionalProperties: false
  50. }
  51. },
  52. additionalProperties: false
  53. },
  54. {
  55. type: "object",
  56. properties: {
  57. array: {
  58. type: "boolean"
  59. },
  60. object: {
  61. type: "boolean"
  62. }
  63. },
  64. additionalProperties: false
  65. }
  66. ]
  67. },
  68. {
  69. type: "object",
  70. properties: {
  71. enforceForRenamedProperties: {
  72. type: "boolean"
  73. }
  74. },
  75. additionalProperties: false
  76. }
  77. ]
  78. },
  79. create(context) {
  80. const enabledTypes = context.options[0];
  81. const enforceForRenamedProperties = context.options[1] && context.options[1].enforceForRenamedProperties;
  82. let normalizedOptions = {
  83. VariableDeclarator: { array: true, object: true },
  84. AssignmentExpression: { array: true, object: true }
  85. };
  86. if (enabledTypes) {
  87. normalizedOptions = typeof enabledTypes.array !== "undefined" || typeof enabledTypes.object !== "undefined"
  88. ? { VariableDeclarator: enabledTypes, AssignmentExpression: enabledTypes }
  89. : enabledTypes;
  90. }
  91. //--------------------------------------------------------------------------
  92. // Helpers
  93. //--------------------------------------------------------------------------
  94. /**
  95. * @param {string} nodeType "AssignmentExpression" or "VariableDeclarator"
  96. * @param {string} destructuringType "array" or "object"
  97. * @returns {boolean} `true` if the destructuring type should be checked for the given node
  98. */
  99. function shouldCheck(nodeType, destructuringType) {
  100. return normalizedOptions &&
  101. normalizedOptions[nodeType] &&
  102. normalizedOptions[nodeType][destructuringType];
  103. }
  104. /**
  105. * Determines if the given node is accessing an array index
  106. *
  107. * This is used to differentiate array index access from object property
  108. * access.
  109. *
  110. * @param {ASTNode} node the node to evaluate
  111. * @returns {boolean} whether or not the node is an integer
  112. */
  113. function isArrayIndexAccess(node) {
  114. return Number.isInteger(node.property.value);
  115. }
  116. /**
  117. * Report that the given node should use destructuring
  118. *
  119. * @param {ASTNode} reportNode the node to report
  120. * @param {string} type the type of destructuring that should have been done
  121. * @returns {void}
  122. */
  123. function report(reportNode, type) {
  124. context.report({ node: reportNode, message: "Use {{type}} destructuring.", data: { type } });
  125. }
  126. /**
  127. * Check that the `prefer-destructuring` rules are followed based on the
  128. * given left- and right-hand side of the assignment.
  129. *
  130. * Pulled out into a separate method so that VariableDeclarators and
  131. * AssignmentExpressions can share the same verification logic.
  132. *
  133. * @param {ASTNode} leftNode the left-hand side of the assignment
  134. * @param {ASTNode} rightNode the right-hand side of the assignment
  135. * @param {ASTNode} reportNode the node to report the error on
  136. * @returns {void}
  137. */
  138. function performCheck(leftNode, rightNode, reportNode) {
  139. if (rightNode.type !== "MemberExpression" || rightNode.object.type === "Super") {
  140. return;
  141. }
  142. if (isArrayIndexAccess(rightNode)) {
  143. if (shouldCheck(reportNode.type, "array")) {
  144. report(reportNode, "array");
  145. }
  146. return;
  147. }
  148. if (shouldCheck(reportNode.type, "object") && enforceForRenamedProperties) {
  149. report(reportNode, "object");
  150. return;
  151. }
  152. if (shouldCheck(reportNode.type, "object")) {
  153. const property = rightNode.property;
  154. if (
  155. (property.type === "Literal" && leftNode.name === property.value) ||
  156. (property.type === "Identifier" && leftNode.name === property.name && !rightNode.computed)
  157. ) {
  158. report(reportNode, "object");
  159. }
  160. }
  161. }
  162. /**
  163. * Check if a given variable declarator is coming from an property access
  164. * that should be using destructuring instead
  165. *
  166. * @param {ASTNode} node the variable declarator to check
  167. * @returns {void}
  168. */
  169. function checkVariableDeclarator(node) {
  170. // Skip if variable is declared without assignment
  171. if (!node.init) {
  172. return;
  173. }
  174. // We only care about member expressions past this point
  175. if (node.init.type !== "MemberExpression") {
  176. return;
  177. }
  178. performCheck(node.id, node.init, node);
  179. }
  180. /**
  181. * Run the `prefer-destructuring` check on an AssignmentExpression
  182. *
  183. * @param {ASTNode} node the AssignmentExpression node
  184. * @returns {void}
  185. */
  186. function checkAssigmentExpression(node) {
  187. if (node.operator === "=") {
  188. performCheck(node.left, node.right, node);
  189. }
  190. }
  191. //--------------------------------------------------------------------------
  192. // Public
  193. //--------------------------------------------------------------------------
  194. return {
  195. VariableDeclarator: checkVariableDeclarator,
  196. AssignmentExpression: checkAssigmentExpression
  197. };
  198. }
  199. };