prefer-reflect.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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('../shared/types').Rule} */
  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/rules/prefer-reflect"
  18. },
  19. deprecated: true,
  20. replacedBy: [],
  21. schema: [
  22. {
  23. type: "object",
  24. properties: {
  25. exceptions: {
  26. type: "array",
  27. items: {
  28. enum: [
  29. "apply",
  30. "call",
  31. "delete",
  32. "defineProperty",
  33. "getOwnPropertyDescriptor",
  34. "getPrototypeOf",
  35. "setPrototypeOf",
  36. "isExtensible",
  37. "getOwnPropertyNames",
  38. "preventExtensions"
  39. ]
  40. },
  41. uniqueItems: true
  42. }
  43. },
  44. additionalProperties: false
  45. }
  46. ],
  47. messages: {
  48. preferReflect: "Avoid using {{existing}}, instead use {{substitute}}."
  49. }
  50. },
  51. create(context) {
  52. const existingNames = {
  53. apply: "Function.prototype.apply",
  54. call: "Function.prototype.call",
  55. defineProperty: "Object.defineProperty",
  56. getOwnPropertyDescriptor: "Object.getOwnPropertyDescriptor",
  57. getPrototypeOf: "Object.getPrototypeOf",
  58. setPrototypeOf: "Object.setPrototypeOf",
  59. isExtensible: "Object.isExtensible",
  60. getOwnPropertyNames: "Object.getOwnPropertyNames",
  61. preventExtensions: "Object.preventExtensions"
  62. };
  63. const reflectSubstitutes = {
  64. apply: "Reflect.apply",
  65. call: "Reflect.apply",
  66. defineProperty: "Reflect.defineProperty",
  67. getOwnPropertyDescriptor: "Reflect.getOwnPropertyDescriptor",
  68. getPrototypeOf: "Reflect.getPrototypeOf",
  69. setPrototypeOf: "Reflect.setPrototypeOf",
  70. isExtensible: "Reflect.isExtensible",
  71. getOwnPropertyNames: "Reflect.getOwnPropertyNames",
  72. preventExtensions: "Reflect.preventExtensions"
  73. };
  74. const exceptions = (context.options[0] || {}).exceptions || [];
  75. /**
  76. * Reports the Reflect violation based on the `existing` and `substitute`
  77. * @param {Object} node The node that violates the rule.
  78. * @param {string} existing The existing method name that has been used.
  79. * @param {string} substitute The Reflect substitute that should be used.
  80. * @returns {void}
  81. */
  82. function report(node, existing, substitute) {
  83. context.report({
  84. node,
  85. messageId: "preferReflect",
  86. data: {
  87. existing,
  88. substitute
  89. }
  90. });
  91. }
  92. return {
  93. CallExpression(node) {
  94. const methodName = (node.callee.property || {}).name;
  95. const isReflectCall = (node.callee.object || {}).name === "Reflect";
  96. const hasReflectSubstitute = Object.prototype.hasOwnProperty.call(reflectSubstitutes, methodName);
  97. const userConfiguredException = exceptions.includes(methodName);
  98. if (hasReflectSubstitute && !isReflectCall && !userConfiguredException) {
  99. report(node, existingNames[methodName], reflectSubstitutes[methodName]);
  100. }
  101. },
  102. UnaryExpression(node) {
  103. const isDeleteOperator = node.operator === "delete";
  104. const targetsIdentifier = node.argument.type === "Identifier";
  105. const userConfiguredException = exceptions.includes("delete");
  106. if (isDeleteOperator && !targetsIdentifier && !userConfiguredException) {
  107. report(node, "the delete keyword", "Reflect.deleteProperty");
  108. }
  109. }
  110. };
  111. }
  112. };