2 * @fileoverview Rule to flag dangling underscores in variable declarations.
3 * @author Matt DuVall <http://www.mattduvall.com>
8 //------------------------------------------------------------------------------
10 //------------------------------------------------------------------------------
17 description: "disallow dangling underscores in identifiers",
18 category: "Stylistic Issues",
20 url: "https://eslint.org/docs/rules/no-underscore-dangle"
41 allowAfterThisConstructor: {
45 enforceInMethodNames: {
49 allowFunctionParams: {
54 additionalProperties: false
59 unexpectedUnderscore: "Unexpected dangling '_' in '{{identifier}}'."
65 const options = context.options[0] || {};
66 const ALLOWED_VARIABLES = options.allow ? options.allow : [];
67 const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false;
68 const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
69 const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
70 const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
71 const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
73 //-------------------------------------------------------------------------
75 //-------------------------------------------------------------------------
78 * Check if identifier is present inside the allowed option
79 * @param {string} identifier name of the node
80 * @returns {boolean} true if its is present
83 function isAllowed(identifier) {
84 return ALLOWED_VARIABLES.some(ident => ident === identifier);
88 * Check if identifier has a dangling underscore
89 * @param {string} identifier name of the node
90 * @returns {boolean} true if its is present
93 function hasDanglingUnderscore(identifier) {
94 const len = identifier.length;
96 return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
100 * Check if identifier is a special case member expression
101 * @param {string} identifier name of the node
102 * @returns {boolean} true if its is a special case
105 function isSpecialCaseIdentifierForMemberExpression(identifier) {
106 return identifier === "__proto__";
110 * Check if identifier is a special case variable expression
111 * @param {string} identifier name of the node
112 * @returns {boolean} true if its is a special case
115 function isSpecialCaseIdentifierInVariableExpression(identifier) {
117 // Checks for the underscore library usage here
118 return identifier === "_";
122 * Check if a node is a member reference of this.constructor
123 * @param {ASTNode} node node to evaluate
124 * @returns {boolean} true if it is a reference on this.constructor
127 function isThisConstructorReference(node) {
128 return node.object.type === "MemberExpression" &&
129 node.object.property.name === "constructor" &&
130 node.object.object.type === "ThisExpression";
134 * Check if function parameter has a dangling underscore.
135 * @param {ASTNode} node function node to evaluate
139 function checkForDanglingUnderscoreInFunctionParameters(node) {
140 if (!allowFunctionParams) {
141 node.params.forEach(param => {
142 const { type } = param;
145 if (type === "RestElement") {
146 nodeToCheck = param.argument;
147 } else if (type === "AssignmentPattern") {
148 nodeToCheck = param.left;
153 if (nodeToCheck.type === "Identifier") {
154 const identifier = nodeToCheck.name;
156 if (hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
159 messageId: "unexpectedUnderscore",
171 * Check if function has a dangling underscore
172 * @param {ASTNode} node node to evaluate
176 function checkForDanglingUnderscoreInFunction(node) {
177 if (node.type === "FunctionDeclaration" && node.id) {
178 const identifier = node.id.name;
180 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
183 messageId: "unexpectedUnderscore",
190 checkForDanglingUnderscoreInFunctionParameters(node);
194 * Check if variable expression has a dangling underscore
195 * @param {ASTNode} node node to evaluate
199 function checkForDanglingUnderscoreInVariableExpression(node) {
200 const identifier = node.id.name;
202 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
203 !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
206 messageId: "unexpectedUnderscore",
215 * Check if member expression has a dangling underscore
216 * @param {ASTNode} node node to evaluate
220 function checkForDanglingUnderscoreInMemberExpression(node) {
221 const identifier = node.property.name,
222 isMemberOfThis = node.object.type === "ThisExpression",
223 isMemberOfSuper = node.object.type === "Super",
224 isMemberOfThisConstructor = isThisConstructorReference(node);
226 if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
227 !(isMemberOfThis && allowAfterThis) &&
228 !(isMemberOfSuper && allowAfterSuper) &&
229 !(isMemberOfThisConstructor && allowAfterThisConstructor) &&
230 !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) {
233 messageId: "unexpectedUnderscore",
242 * Check if method declaration or method property has a dangling underscore
243 * @param {ASTNode} node node to evaluate
247 function checkForDanglingUnderscoreInMethod(node) {
248 const identifier = node.key.name;
249 const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method;
251 if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
254 messageId: "unexpectedUnderscore",
262 //--------------------------------------------------------------------------
264 //--------------------------------------------------------------------------
267 FunctionDeclaration: checkForDanglingUnderscoreInFunction,
268 VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
269 MemberExpression: checkForDanglingUnderscoreInMemberExpression,
270 MethodDefinition: checkForDanglingUnderscoreInMethod,
271 Property: checkForDanglingUnderscoreInMethod,
272 FunctionExpression: checkForDanglingUnderscoreInFunction,
273 ArrowFunctionExpression: checkForDanglingUnderscoreInFunction