blob: 157f0bbd61a84e65e4fc76cac169073d9fd1a05b [file] [log] [blame]
Yang Guo4fd355c2019-09-19 10:59:03 +02001/**
2 * @fileoverview Rule to
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Helpers
10//------------------------------------------------------------------------------
11
12/**
13 * Gets the variable object of `arguments` which is defined implicitly.
Tim van der Lippec8f6ffd2020-04-06 13:42:00 +010014 * @param {eslint-scope.Scope} scope A scope to get.
Yang Guo4fd355c2019-09-19 10:59:03 +020015 * @returns {eslint-scope.Variable} The found variable object.
16 */
17function getVariableOfArguments(scope) {
18 const variables = scope.variables;
19
20 for (let i = 0; i < variables.length; ++i) {
21 const variable = variables[i];
22
23 if (variable.name === "arguments") {
24
25 /*
26 * If there was a parameter which is named "arguments", the implicit "arguments" is not defined.
27 * So does fast return with null.
28 */
29 return (variable.identifiers.length === 0) ? variable : null;
30 }
31 }
32
33 /* istanbul ignore next : unreachable */
34 return null;
35}
36
37/**
38 * Checks if the given reference is not normal member access.
39 *
40 * - arguments .... true // not member access
41 * - arguments[i] .... true // computed member access
42 * - arguments[0] .... true // computed member access
43 * - arguments.length .... false // normal member access
Tim van der Lippec8f6ffd2020-04-06 13:42:00 +010044 * @param {eslint-scope.Reference} reference The reference to check.
Yang Guo4fd355c2019-09-19 10:59:03 +020045 * @returns {boolean} `true` if the reference is not normal member access.
46 */
47function isNotNormalMemberAccess(reference) {
48 const id = reference.identifier;
49 const parent = id.parent;
50
51 return !(
52 parent.type === "MemberExpression" &&
53 parent.object === id &&
54 !parent.computed
55 );
56}
57
58//------------------------------------------------------------------------------
59// Rule Definition
60//------------------------------------------------------------------------------
61
62module.exports = {
63 meta: {
64 type: "suggestion",
65
66 docs: {
67 description: "require rest parameters instead of `arguments`",
Yang Guo4fd355c2019-09-19 10:59:03 +020068 recommended: false,
69 url: "https://eslint.org/docs/rules/prefer-rest-params"
70 },
71
Tim van der Lippe16aca392020-11-13 11:37:13 +000072 schema: [],
73
74 messages: {
75 preferRestParams: "Use the rest parameters instead of 'arguments'."
76 }
Yang Guo4fd355c2019-09-19 10:59:03 +020077 },
78
79 create(context) {
80
81 /**
82 * Reports a given reference.
Tim van der Lippec8f6ffd2020-04-06 13:42:00 +010083 * @param {eslint-scope.Reference} reference A reference to report.
Yang Guo4fd355c2019-09-19 10:59:03 +020084 * @returns {void}
85 */
86 function report(reference) {
87 context.report({
88 node: reference.identifier,
89 loc: reference.identifier.loc,
Tim van der Lippe16aca392020-11-13 11:37:13 +000090 messageId: "preferRestParams"
Yang Guo4fd355c2019-09-19 10:59:03 +020091 });
92 }
93
94 /**
95 * Reports references of the implicit `arguments` variable if exist.
Yang Guo4fd355c2019-09-19 10:59:03 +020096 * @returns {void}
97 */
98 function checkForArguments() {
99 const argumentsVar = getVariableOfArguments(context.getScope());
100
101 if (argumentsVar) {
102 argumentsVar
103 .references
104 .filter(isNotNormalMemberAccess)
105 .forEach(report);
106 }
107 }
108
109 return {
110 "FunctionDeclaration:exit": checkForArguments,
111 "FunctionExpression:exit": checkForArguments
112 };
113 }
114};