prefer-rest-params.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. /* istanbul ignore next : unreachable */
  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. module.exports = {
  52. meta: {
  53. type: "suggestion",
  54. docs: {
  55. description: "require rest parameters instead of `arguments`",
  56. category: "ECMAScript 6",
  57. recommended: false,
  58. url: "https://eslint.org/docs/rules/prefer-rest-params"
  59. },
  60. schema: []
  61. },
  62. create(context) {
  63. /**
  64. * Reports a given reference.
  65. * @param {eslint-scope.Reference} reference A reference to report.
  66. * @returns {void}
  67. */
  68. function report(reference) {
  69. context.report({
  70. node: reference.identifier,
  71. loc: reference.identifier.loc,
  72. message: "Use the rest parameters instead of 'arguments'."
  73. });
  74. }
  75. /**
  76. * Reports references of the implicit `arguments` variable if exist.
  77. * @returns {void}
  78. */
  79. function checkForArguments() {
  80. const argumentsVar = getVariableOfArguments(context.getScope());
  81. if (argumentsVar) {
  82. argumentsVar
  83. .references
  84. .filter(isNotNormalMemberAccess)
  85. .forEach(report);
  86. }
  87. }
  88. return {
  89. "FunctionDeclaration:exit": checkForArguments,
  90. "FunctionExpression:exit": checkForArguments
  91. };
  92. }
  93. };