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