prefer-rest-params.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * @fileoverview Rule to
  3. * @author Toru Nagashima
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Helpers
  8. //------------------------------------------------------------------------------
  9. /**
  10. * Gets the variable object of `arguments` which is defined implicitly.
  11. * @param {eslint-scope.Scope} scope A scope to get.
  12. * @returns {eslint-scope.Variable} The found variable object.
  13. */
  14. function getVariableOfArguments(scope) {
  15. const variables = scope.variables;
  16. for (let i = 0; i < variables.length; ++i) {
  17. const variable = variables[i];
  18. if (variable.name === "arguments") {
  19. /*
  20. * If there was a parameter which is named "arguments", the implicit "arguments" is not defined.
  21. * So does fast return with null.
  22. */
  23. return (variable.identifiers.length === 0) ? variable : null;
  24. }
  25. }
  26. /* c8 ignore next */
  27. return null;
  28. }
  29. /**
  30. * Checks if the given reference is not normal member access.
  31. *
  32. * - arguments .... true // not member access
  33. * - arguments[i] .... true // computed member access
  34. * - arguments[0] .... true // computed member access
  35. * - arguments.length .... false // normal member access
  36. * @param {eslint-scope.Reference} reference The reference to check.
  37. * @returns {boolean} `true` if the reference is not normal member access.
  38. */
  39. function isNotNormalMemberAccess(reference) {
  40. const id = reference.identifier;
  41. const parent = id.parent;
  42. return !(
  43. parent.type === "MemberExpression" &&
  44. parent.object === id &&
  45. !parent.computed
  46. );
  47. }
  48. //------------------------------------------------------------------------------
  49. // Rule Definition
  50. //------------------------------------------------------------------------------
  51. /** @type {import('../shared/types').Rule} */
  52. module.exports = {
  53. meta: {
  54. type: "suggestion",
  55. docs: {
  56. description: "Require rest parameters instead of `arguments`",
  57. recommended: false,
  58. url: "https://eslint.org/docs/rules/prefer-rest-params"
  59. },
  60. schema: [],
  61. messages: {
  62. preferRestParams: "Use the rest parameters instead of 'arguments'."
  63. }
  64. },
  65. create(context) {
  66. /**
  67. * Reports a given reference.
  68. * @param {eslint-scope.Reference} reference A reference to report.
  69. * @returns {void}
  70. */
  71. function report(reference) {
  72. context.report({
  73. node: reference.identifier,
  74. loc: reference.identifier.loc,
  75. messageId: "preferRestParams"
  76. });
  77. }
  78. /**
  79. * Reports references of the implicit `arguments` variable if exist.
  80. * @returns {void}
  81. */
  82. function checkForArguments() {
  83. const argumentsVar = getVariableOfArguments(context.getScope());
  84. if (argumentsVar) {
  85. argumentsVar
  86. .references
  87. .filter(isNotNormalMemberAccess)
  88. .forEach(report);
  89. }
  90. }
  91. return {
  92. "FunctionDeclaration:exit": checkForArguments,
  93. "FunctionExpression:exit": checkForArguments
  94. };
  95. }
  96. };