• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
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.
14 * @param {eslint-scope.Scope} scope A scope to get.
15 * @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
44 * @param {eslint-scope.Reference} reference The reference to check.
45 * @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`",
68            category: "ECMAScript 6",
69            recommended: false,
70            url: "https://eslint.org/docs/rules/prefer-rest-params"
71        },
72
73        schema: [],
74
75        messages: {
76            preferRestParams: "Use the rest parameters instead of 'arguments'."
77        }
78    },
79
80    create(context) {
81
82        /**
83         * Reports a given reference.
84         * @param {eslint-scope.Reference} reference A reference to report.
85         * @returns {void}
86         */
87        function report(reference) {
88            context.report({
89                node: reference.identifier,
90                loc: reference.identifier.loc,
91                messageId: "preferRestParams"
92            });
93        }
94
95        /**
96         * Reports references of the implicit `arguments` variable if exist.
97         * @returns {void}
98         */
99        function checkForArguments() {
100            const argumentsVar = getVariableOfArguments(context.getScope());
101
102            if (argumentsVar) {
103                argumentsVar
104                    .references
105                    .filter(isNotNormalMemberAccess)
106                    .forEach(report);
107            }
108        }
109
110        return {
111            "FunctionDeclaration:exit": checkForArguments,
112            "FunctionExpression:exit": checkForArguments
113        };
114    }
115};
116