prefer-reflect.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /**
  2. * @fileoverview Rule to suggest using "Reflect" api over Function/Object methods
  3. * @author Keith Cirkel <http://keithcirkel.co.uk>
  4. * @deprecated in ESLint v3.9.0
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. /** @type {import('../types').Rule.RuleModule} */
  11. module.exports = {
  12. meta: {
  13. type: "suggestion",
  14. docs: {
  15. description: "Require `Reflect` methods where applicable",
  16. recommended: false,
  17. url: "https://eslint.org/docs/latest/rules/prefer-reflect",
  18. },
  19. deprecated: {
  20. message: "The original intention of this rule was misguided.",
  21. deprecatedSince: "3.9.0",
  22. availableUntil: null,
  23. replacedBy: [],
  24. },
  25. schema: [
  26. {
  27. type: "object",
  28. properties: {
  29. exceptions: {
  30. type: "array",
  31. items: {
  32. enum: [
  33. "apply",
  34. "call",
  35. "delete",
  36. "defineProperty",
  37. "getOwnPropertyDescriptor",
  38. "getPrototypeOf",
  39. "setPrototypeOf",
  40. "isExtensible",
  41. "getOwnPropertyNames",
  42. "preventExtensions",
  43. ],
  44. },
  45. uniqueItems: true,
  46. },
  47. },
  48. additionalProperties: false,
  49. },
  50. ],
  51. messages: {
  52. preferReflect:
  53. "Avoid using {{existing}}, instead use {{substitute}}.",
  54. },
  55. },
  56. create(context) {
  57. const existingNames = {
  58. apply: "Function.prototype.apply",
  59. call: "Function.prototype.call",
  60. defineProperty: "Object.defineProperty",
  61. getOwnPropertyDescriptor: "Object.getOwnPropertyDescriptor",
  62. getPrototypeOf: "Object.getPrototypeOf",
  63. setPrototypeOf: "Object.setPrototypeOf",
  64. isExtensible: "Object.isExtensible",
  65. getOwnPropertyNames: "Object.getOwnPropertyNames",
  66. preventExtensions: "Object.preventExtensions",
  67. };
  68. const reflectSubstitutes = {
  69. apply: "Reflect.apply",
  70. call: "Reflect.apply",
  71. defineProperty: "Reflect.defineProperty",
  72. getOwnPropertyDescriptor: "Reflect.getOwnPropertyDescriptor",
  73. getPrototypeOf: "Reflect.getPrototypeOf",
  74. setPrototypeOf: "Reflect.setPrototypeOf",
  75. isExtensible: "Reflect.isExtensible",
  76. getOwnPropertyNames: "Reflect.getOwnPropertyNames",
  77. preventExtensions: "Reflect.preventExtensions",
  78. };
  79. const exceptions = (context.options[0] || {}).exceptions || [];
  80. /**
  81. * Reports the Reflect violation based on the `existing` and `substitute`
  82. * @param {Object} node The node that violates the rule.
  83. * @param {string} existing The existing method name that has been used.
  84. * @param {string} substitute The Reflect substitute that should be used.
  85. * @returns {void}
  86. */
  87. function report(node, existing, substitute) {
  88. context.report({
  89. node,
  90. messageId: "preferReflect",
  91. data: {
  92. existing,
  93. substitute,
  94. },
  95. });
  96. }
  97. return {
  98. CallExpression(node) {
  99. const methodName = (node.callee.property || {}).name;
  100. const isReflectCall =
  101. (node.callee.object || {}).name === "Reflect";
  102. const hasReflectSubstitute = Object.hasOwn(
  103. reflectSubstitutes,
  104. methodName,
  105. );
  106. const userConfiguredException = exceptions.includes(methodName);
  107. if (
  108. hasReflectSubstitute &&
  109. !isReflectCall &&
  110. !userConfiguredException
  111. ) {
  112. report(
  113. node,
  114. existingNames[methodName],
  115. reflectSubstitutes[methodName],
  116. );
  117. }
  118. },
  119. UnaryExpression(node) {
  120. const isDeleteOperator = node.operator === "delete";
  121. const targetsIdentifier = node.argument.type === "Identifier";
  122. const userConfiguredException = exceptions.includes("delete");
  123. if (
  124. isDeleteOperator &&
  125. !targetsIdentifier &&
  126. !userConfiguredException
  127. ) {
  128. report(
  129. node,
  130. "the delete keyword",
  131. "Reflect.deleteProperty",
  132. );
  133. }
  134. },
  135. };
  136. },
  137. };