2 * @fileoverview Rule to flag trailing 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: {
50 additionalProperties: false
57 const options = context.options[0] || {};
58 const ALLOWED_VARIABLES = options.allow ? options.allow : [];
59 const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false;
60 const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
61 const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
62 const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
64 //-------------------------------------------------------------------------
66 //-------------------------------------------------------------------------
69 * Check if identifier is present inside the allowed option
70 * @param {string} identifier name of the node
71 * @returns {boolean} true if its is present
74 function isAllowed(identifier) {
75 return ALLOWED_VARIABLES.some(ident => ident === identifier);
79 * Check if identifier has a underscore at the end
80 * @param {string} identifier name of the node
81 * @returns {boolean} true if its is present
84 function hasTrailingUnderscore(identifier) {
85 const len = identifier.length;
87 return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
91 * Check if identifier is a special case member expression
92 * @param {string} identifier name of the node
93 * @returns {boolean} true if its is a special case
96 function isSpecialCaseIdentifierForMemberExpression(identifier) {
97 return identifier === "__proto__";
101 * Check if identifier is a special case variable expression
102 * @param {string} identifier name of the node
103 * @returns {boolean} true if its is a special case
106 function isSpecialCaseIdentifierInVariableExpression(identifier) {
108 // Checks for the underscore library usage here
109 return identifier === "_";
113 * Check if a node is a member reference of this.constructor
114 * @param {ASTNode} node node to evaluate
115 * @returns {boolean} true if it is a reference on this.constructor
118 function isThisConstructorReference(node) {
119 return node.object.type === "MemberExpression" &&
120 node.object.property.name === "constructor" &&
121 node.object.object.type === "ThisExpression";
125 * Check if function has a underscore at the end
126 * @param {ASTNode} node node to evaluate
130 function checkForTrailingUnderscoreInFunctionDeclaration(node) {
132 const identifier = node.id.name;
134 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) {
137 message: "Unexpected dangling '_' in '{{identifier}}'.",
147 * Check if variable expression has a underscore at the end
148 * @param {ASTNode} node node to evaluate
152 function checkForTrailingUnderscoreInVariableExpression(node) {
153 const identifier = node.id.name;
155 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
156 !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
159 message: "Unexpected dangling '_' in '{{identifier}}'.",
168 * Check if member expression has a underscore at the end
169 * @param {ASTNode} node node to evaluate
173 function checkForTrailingUnderscoreInMemberExpression(node) {
174 const identifier = node.property.name,
175 isMemberOfThis = node.object.type === "ThisExpression",
176 isMemberOfSuper = node.object.type === "Super",
177 isMemberOfThisConstructor = isThisConstructorReference(node);
179 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
180 !(isMemberOfThis && allowAfterThis) &&
181 !(isMemberOfSuper && allowAfterSuper) &&
182 !(isMemberOfThisConstructor && allowAfterThisConstructor) &&
183 !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) {
186 message: "Unexpected dangling '_' in '{{identifier}}'.",
195 * Check if method declaration or method property has a underscore at the end
196 * @param {ASTNode} node node to evaluate
200 function checkForTrailingUnderscoreInMethod(node) {
201 const identifier = node.key.name;
202 const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method;
204 if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasTrailingUnderscore(identifier)) {
207 message: "Unexpected dangling '_' in '{{identifier}}'.",
215 //--------------------------------------------------------------------------
217 //--------------------------------------------------------------------------
220 FunctionDeclaration: checkForTrailingUnderscoreInFunctionDeclaration,
221 VariableDeclarator: checkForTrailingUnderscoreInVariableExpression,
222 MemberExpression: checkForTrailingUnderscoreInMemberExpression,
223 MethodDefinition: checkForTrailingUnderscoreInMethod,
224 Property: checkForTrailingUnderscoreInMethod