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

accessor-pairs.js 5.1 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * @fileoverview Rule to flag wrapping non-iife in parens
  3. * @author Gyandeep Singh
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Helpers
  8. //------------------------------------------------------------------------------
  9. /**
  10. * Checks whether or not a given node is an `Identifier` node which was named a given name.
  11. * @param {ASTNode} node - A node to check.
  12. * @param {string} name - An expected name of the node.
  13. * @returns {boolean} `true` if the node is an `Identifier` node which was named as expected.
  14. */
  15. function isIdentifier(node, name) {
  16. return node.type === "Identifier" && node.name === name;
  17. }
  18. /**
  19. * Checks whether or not a given node is an argument of a specified method call.
  20. * @param {ASTNode} node - A node to check.
  21. * @param {number} index - An expected index of the node in arguments.
  22. * @param {string} object - An expected name of the object of the method.
  23. * @param {string} property - An expected name of the method.
  24. * @returns {boolean} `true` if the node is an argument of the specified method call.
  25. */
  26. function isArgumentOfMethodCall(node, index, object, property) {
  27. const parent = node.parent;
  28. return (
  29. parent.type === "CallExpression" &&
  30. parent.callee.type === "MemberExpression" &&
  31. parent.callee.computed === false &&
  32. isIdentifier(parent.callee.object, object) &&
  33. isIdentifier(parent.callee.property, property) &&
  34. parent.arguments[index] === node
  35. );
  36. }
  37. /**
  38. * Checks whether or not a given node is a property descriptor.
  39. * @param {ASTNode} node - A node to check.
  40. * @returns {boolean} `true` if the node is a property descriptor.
  41. */
  42. function isPropertyDescriptor(node) {
  43. // Object.defineProperty(obj, "foo", {set: ...})
  44. if (isArgumentOfMethodCall(node, 2, "Object", "defineProperty") ||
  45. isArgumentOfMethodCall(node, 2, "Reflect", "defineProperty")
  46. ) {
  47. return true;
  48. }
  49. /*
  50. * Object.defineProperties(obj, {foo: {set: ...}})
  51. * Object.create(proto, {foo: {set: ...}})
  52. */
  53. const grandparent = node.parent.parent;
  54. return grandparent.type === "ObjectExpression" && (
  55. isArgumentOfMethodCall(grandparent, 1, "Object", "create") ||
  56. isArgumentOfMethodCall(grandparent, 1, "Object", "defineProperties")
  57. );
  58. }
  59. //------------------------------------------------------------------------------
  60. // Rule Definition
  61. //------------------------------------------------------------------------------
  62. module.exports = {
  63. meta: {
  64. docs: {
  65. description: "enforce getter and setter pairs in objects",
  66. category: "Best Practices",
  67. recommended: false,
  68. url: "https://eslint.org/docs/rules/accessor-pairs"
  69. },
  70. schema: [{
  71. type: "object",
  72. properties: {
  73. getWithoutSet: {
  74. type: "boolean"
  75. },
  76. setWithoutGet: {
  77. type: "boolean"
  78. }
  79. },
  80. additionalProperties: false
  81. }],
  82. messages: {
  83. getter: "Getter is not present.",
  84. setter: "Setter is not present."
  85. }
  86. },
  87. create(context) {
  88. const config = context.options[0] || {};
  89. const checkGetWithoutSet = config.getWithoutSet === true;
  90. const checkSetWithoutGet = config.setWithoutGet !== false;
  91. /**
  92. * Checks a object expression to see if it has setter and getter both present or none.
  93. * @param {ASTNode} node The node to check.
  94. * @returns {void}
  95. * @private
  96. */
  97. function checkLonelySetGet(node) {
  98. let isSetPresent = false;
  99. let isGetPresent = false;
  100. const isDescriptor = isPropertyDescriptor(node);
  101. for (let i = 0, end = node.properties.length; i < end; i++) {
  102. const property = node.properties[i];
  103. let propToCheck = "";
  104. if (property.kind === "init") {
  105. if (isDescriptor && !property.computed) {
  106. propToCheck = property.key.name;
  107. }
  108. } else {
  109. propToCheck = property.kind;
  110. }
  111. switch (propToCheck) {
  112. case "set":
  113. isSetPresent = true;
  114. break;
  115. case "get":
  116. isGetPresent = true;
  117. break;
  118. default:
  119. // Do nothing
  120. }
  121. if (isSetPresent && isGetPresent) {
  122. break;
  123. }
  124. }
  125. if (checkSetWithoutGet && isSetPresent && !isGetPresent) {
  126. context.report({ node, messageId: "getter" });
  127. } else if (checkGetWithoutSet && isGetPresent && !isSetPresent) {
  128. context.report({ node, messageId: "setter" });
  129. }
  130. }
  131. return {
  132. ObjectExpression(node) {
  133. if (checkSetWithoutGet || checkGetWithoutSet) {
  134. checkLonelySetGet(node);
  135. }
  136. }
  137. };
  138. }
  139. };