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

116 lines
3.5 KiB

  1. /**
  2. * @fileoverview Rule to enforce that all class methods use 'this'.
  3. * @author Patrick Williams
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. module.exports = {
  10. meta: {
  11. docs: {
  12. description: "enforce that class methods utilize `this`",
  13. category: "Best Practices",
  14. recommended: false,
  15. url: "https://eslint.org/docs/rules/class-methods-use-this"
  16. },
  17. schema: [{
  18. type: "object",
  19. properties: {
  20. exceptMethods: {
  21. type: "array",
  22. items: {
  23. type: "string"
  24. }
  25. }
  26. },
  27. additionalProperties: false
  28. }],
  29. messages: {
  30. missingThis: "Expected 'this' to be used by class method '{{name}}'."
  31. }
  32. },
  33. create(context) {
  34. const config = context.options[0] ? Object.assign({}, context.options[0]) : {};
  35. const exceptMethods = new Set(config.exceptMethods || []);
  36. const stack = [];
  37. /**
  38. * Initializes the current context to false and pushes it onto the stack.
  39. * These booleans represent whether 'this' has been used in the context.
  40. * @returns {void}
  41. * @private
  42. */
  43. function enterFunction() {
  44. stack.push(false);
  45. }
  46. /**
  47. * Check if the node is an instance method
  48. * @param {ASTNode} node - node to check
  49. * @returns {boolean} True if its an instance method
  50. * @private
  51. */
  52. function isInstanceMethod(node) {
  53. return !node.static && node.kind !== "constructor" && node.type === "MethodDefinition";
  54. }
  55. /**
  56. * Check if the node is an instance method not excluded by config
  57. * @param {ASTNode} node - node to check
  58. * @returns {boolean} True if it is an instance method, and not excluded by config
  59. * @private
  60. */
  61. function isIncludedInstanceMethod(node) {
  62. return isInstanceMethod(node) && !exceptMethods.has(node.key.name);
  63. }
  64. /**
  65. * Checks if we are leaving a function that is a method, and reports if 'this' has not been used.
  66. * Static methods and the constructor are exempt.
  67. * Then pops the context off the stack.
  68. * @param {ASTNode} node - A function node that was entered.
  69. * @returns {void}
  70. * @private
  71. */
  72. function exitFunction(node) {
  73. const methodUsesThis = stack.pop();
  74. if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
  75. context.report({
  76. node,
  77. messageId: "missingThis",
  78. data: {
  79. name: node.parent.key.name
  80. }
  81. });
  82. }
  83. }
  84. /**
  85. * Mark the current context as having used 'this'.
  86. * @returns {void}
  87. * @private
  88. */
  89. function markThisUsed() {
  90. if (stack.length) {
  91. stack[stack.length - 1] = true;
  92. }
  93. }
  94. return {
  95. FunctionDeclaration: enterFunction,
  96. "FunctionDeclaration:exit": exitFunction,
  97. FunctionExpression: enterFunction,
  98. "FunctionExpression:exit": exitFunction,
  99. ThisExpression: markThisUsed,
  100. Super: markThisUsed
  101. };
  102. }
  103. };