| /** |
| * @fileoverview Rule to flag trailing underscores in variable declarations. |
| * @author Matt DuVall <http://www.mattduvall.com> |
| */ |
| |
| "use strict"; |
| |
| //------------------------------------------------------------------------------ |
| // Rule Definition |
| //------------------------------------------------------------------------------ |
| |
| module.exports = { |
| meta: { |
| type: "suggestion", |
| |
| docs: { |
| description: "disallow dangling underscores in identifiers", |
| category: "Stylistic Issues", |
| recommended: false, |
| url: "https://eslint.org/docs/rules/no-underscore-dangle" |
| }, |
| |
| schema: [ |
| { |
| type: "object", |
| properties: { |
| allow: { |
| type: "array", |
| items: { |
| type: "string" |
| } |
| }, |
| allowAfterThis: { |
| type: "boolean", |
| default: false |
| }, |
| allowAfterSuper: { |
| type: "boolean", |
| default: false |
| }, |
| enforceInMethodNames: { |
| type: "boolean", |
| default: false |
| } |
| }, |
| additionalProperties: false |
| } |
| ] |
| }, |
| |
| create(context) { |
| |
| const options = context.options[0] || {}; |
| const ALLOWED_VARIABLES = options.allow ? options.allow : []; |
| const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; |
| const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false; |
| const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false; |
| |
| //------------------------------------------------------------------------- |
| // Helpers |
| //------------------------------------------------------------------------- |
| |
| /** |
| * Check if identifier is present inside the allowed option |
| * @param {string} identifier name of the node |
| * @returns {boolean} true if its is present |
| * @private |
| */ |
| function isAllowed(identifier) { |
| return ALLOWED_VARIABLES.some(ident => ident === identifier); |
| } |
| |
| /** |
| * Check if identifier has a underscore at the end |
| * @param {ASTNode} identifier node to evaluate |
| * @returns {boolean} true if its is present |
| * @private |
| */ |
| function hasTrailingUnderscore(identifier) { |
| const len = identifier.length; |
| |
| return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_"); |
| } |
| |
| /** |
| * Check if identifier is a special case member expression |
| * @param {ASTNode} identifier node to evaluate |
| * @returns {boolean} true if its is a special case |
| * @private |
| */ |
| function isSpecialCaseIdentifierForMemberExpression(identifier) { |
| return identifier === "__proto__"; |
| } |
| |
| /** |
| * Check if identifier is a special case variable expression |
| * @param {ASTNode} identifier node to evaluate |
| * @returns {boolean} true if its is a special case |
| * @private |
| */ |
| function isSpecialCaseIdentifierInVariableExpression(identifier) { |
| |
| // Checks for the underscore library usage here |
| return identifier === "_"; |
| } |
| |
| /** |
| * Check if function has a underscore at the end |
| * @param {ASTNode} node node to evaluate |
| * @returns {void} |
| * @private |
| */ |
| function checkForTrailingUnderscoreInFunctionDeclaration(node) { |
| if (node.id) { |
| const identifier = node.id.name; |
| |
| if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) { |
| context.report({ |
| node, |
| message: "Unexpected dangling '_' in '{{identifier}}'.", |
| data: { |
| identifier |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * Check if variable expression has a underscore at the end |
| * @param {ASTNode} node node to evaluate |
| * @returns {void} |
| * @private |
| */ |
| function checkForTrailingUnderscoreInVariableExpression(node) { |
| const identifier = node.id.name; |
| |
| if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && |
| !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) { |
| context.report({ |
| node, |
| message: "Unexpected dangling '_' in '{{identifier}}'.", |
| data: { |
| identifier |
| } |
| }); |
| } |
| } |
| |
| /** |
| * Check if member expression has a underscore at the end |
| * @param {ASTNode} node node to evaluate |
| * @returns {void} |
| * @private |
| */ |
| function checkForTrailingUnderscoreInMemberExpression(node) { |
| const identifier = node.property.name, |
| isMemberOfThis = node.object.type === "ThisExpression", |
| isMemberOfSuper = node.object.type === "Super"; |
| |
| if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && |
| !(isMemberOfThis && allowAfterThis) && |
| !(isMemberOfSuper && allowAfterSuper) && |
| !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) { |
| context.report({ |
| node, |
| message: "Unexpected dangling '_' in '{{identifier}}'.", |
| data: { |
| identifier |
| } |
| }); |
| } |
| } |
| |
| /** |
| * Check if method declaration or method property has a underscore at the end |
| * @param {ASTNode} node node to evaluate |
| * @returns {void} |
| * @private |
| */ |
| function checkForTrailingUnderscoreInMethod(node) { |
| const identifier = node.key.name; |
| const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method; |
| |
| if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasTrailingUnderscore(identifier)) { |
| context.report({ |
| node, |
| message: "Unexpected dangling '_' in '{{identifier}}'.", |
| data: { |
| identifier |
| } |
| }); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // Public API |
| //-------------------------------------------------------------------------- |
| |
| return { |
| FunctionDeclaration: checkForTrailingUnderscoreInFunctionDeclaration, |
| VariableDeclarator: checkForTrailingUnderscoreInVariableExpression, |
| MemberExpression: checkForTrailingUnderscoreInMemberExpression, |
| MethodDefinition: checkForTrailingUnderscoreInMethod, |
| Property: checkForTrailingUnderscoreInMethod |
| }; |
| |
| } |
| }; |