codtracker-js/node_modules/eslint/lib/rules/no-underscore-dangle.js
2025-04-19 23:12:19 -04:00

372 lines
10 KiB
JavaScript

/**
* @fileoverview Rule to flag dangling underscores in variable declarations.
* @author Matt DuVall <http://www.mattduvall.com>
*/
'use strict';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: 'suggestion',
defaultOptions: [
{
allow: [],
allowAfterSuper: false,
allowAfterThis: false,
allowAfterThisConstructor: false,
allowFunctionParams: true,
allowInArrayDestructuring: true,
allowInObjectDestructuring: true,
enforceInClassFields: false,
enforceInMethodNames: false,
},
],
docs: {
description: 'Disallow dangling underscores in identifiers',
recommended: false,
frozen: true,
url: 'https://eslint.org/docs/latest/rules/no-underscore-dangle',
},
schema: [
{
type: 'object',
properties: {
allow: {
type: 'array',
items: {
type: 'string',
},
},
allowAfterThis: {
type: 'boolean',
},
allowAfterSuper: {
type: 'boolean',
},
allowAfterThisConstructor: {
type: 'boolean',
},
enforceInMethodNames: {
type: 'boolean',
},
allowFunctionParams: {
type: 'boolean',
},
enforceInClassFields: {
type: 'boolean',
},
allowInArrayDestructuring: {
type: 'boolean',
},
allowInObjectDestructuring: {
type: 'boolean',
},
},
additionalProperties: false,
},
],
messages: {
unexpectedUnderscore: "Unexpected dangling '_' in '{{identifier}}'.",
},
},
create(context) {
const [
{
allow,
allowAfterSuper,
allowAfterThis,
allowAfterThisConstructor,
allowFunctionParams,
allowInArrayDestructuring,
allowInObjectDestructuring,
enforceInClassFields,
enforceInMethodNames,
},
] = context.options;
const sourceCode = context.sourceCode;
//-------------------------------------------------------------------------
// 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 allow.includes(identifier);
}
/**
* Check if identifier has a dangling underscore
* @param {string} identifier name of the node
* @returns {boolean} true if its is present
* @private
*/
function hasDanglingUnderscore(identifier) {
const len = identifier.length;
return (
identifier !== '_' &&
(identifier[0] === '_' || identifier[len - 1] === '_')
);
}
/**
* Check if identifier is a special case member expression
* @param {string} identifier name of the node
* @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 {string} identifier name of the node
* @returns {boolean} true if its is a special case
* @private
*/
function isSpecialCaseIdentifierInVariableExpression(identifier) {
// Checks for the underscore library usage here
return identifier === '_';
}
/**
* Check if a node is a member reference of this.constructor
* @param {ASTNode} node node to evaluate
* @returns {boolean} true if it is a reference on this.constructor
* @private
*/
function isThisConstructorReference(node) {
return (
node.object.type === 'MemberExpression' &&
node.object.property.name === 'constructor' &&
node.object.object.type === 'ThisExpression'
);
}
/**
* Check if function parameter has a dangling underscore.
* @param {ASTNode} node function node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInFunctionParameters(node) {
if (!allowFunctionParams) {
node.params.forEach((param) => {
const { type } = param;
let nodeToCheck;
if (type === 'RestElement') {
nodeToCheck = param.argument;
} else if (type === 'AssignmentPattern') {
nodeToCheck = param.left;
} else {
nodeToCheck = param;
}
if (nodeToCheck.type === 'Identifier') {
const identifier = nodeToCheck.name;
if (hasDanglingUnderscore(identifier) && !isAllowed(identifier)) {
context.report({
node: param,
messageId: 'unexpectedUnderscore',
data: {
identifier,
},
});
}
}
});
}
}
/**
* Check if function has a dangling underscore
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInFunction(node) {
if (node.type === 'FunctionDeclaration' && node.id) {
const identifier = node.id.name;
if (
typeof identifier !== 'undefined' &&
hasDanglingUnderscore(identifier) &&
!isAllowed(identifier)
) {
context.report({
node,
messageId: 'unexpectedUnderscore',
data: {
identifier,
},
});
}
}
checkForDanglingUnderscoreInFunctionParameters(node);
}
/**
* Check if variable expression has a dangling underscore
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInVariableExpression(node) {
sourceCode.getDeclaredVariables(node).forEach((variable) => {
const definition = variable.defs.find((def) => def.node === node);
const identifierNode = definition.name;
const identifier = identifierNode.name;
let parent = identifierNode.parent;
while (
!['VariableDeclarator', 'ArrayPattern', 'ObjectPattern'].includes(
parent.type
)
) {
parent = parent.parent;
}
if (
hasDanglingUnderscore(identifier) &&
!isSpecialCaseIdentifierInVariableExpression(identifier) &&
!isAllowed(identifier) &&
!(allowInArrayDestructuring && parent.type === 'ArrayPattern') &&
!(allowInObjectDestructuring && parent.type === 'ObjectPattern')
) {
context.report({
node,
messageId: 'unexpectedUnderscore',
data: {
identifier,
},
});
}
});
}
/**
* Check if member expression has a dangling underscore
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInMemberExpression(node) {
const identifier = node.property.name,
isMemberOfThis = node.object.type === 'ThisExpression',
isMemberOfSuper = node.object.type === 'Super',
isMemberOfThisConstructor = isThisConstructorReference(node);
if (
typeof identifier !== 'undefined' &&
hasDanglingUnderscore(identifier) &&
!(isMemberOfThis && allowAfterThis) &&
!(isMemberOfSuper && allowAfterSuper) &&
!(isMemberOfThisConstructor && allowAfterThisConstructor) &&
!isSpecialCaseIdentifierForMemberExpression(identifier) &&
!isAllowed(identifier)
) {
context.report({
node,
messageId: 'unexpectedUnderscore',
data: {
identifier,
},
});
}
}
/**
* Check if method declaration or method property has a dangling underscore
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInMethod(node) {
const identifier = node.key.name;
const isMethod =
node.type === 'MethodDefinition' ||
(node.type === 'Property' && node.method);
if (
typeof identifier !== 'undefined' &&
enforceInMethodNames &&
isMethod &&
hasDanglingUnderscore(identifier) &&
!isAllowed(identifier)
) {
context.report({
node,
messageId: 'unexpectedUnderscore',
data: {
identifier:
node.key.type === 'PrivateIdentifier' ?
`#${identifier}`
: identifier,
},
});
}
}
/**
* Check if a class field has a dangling underscore
* @param {ASTNode} node node to evaluate
* @returns {void}
* @private
*/
function checkForDanglingUnderscoreInClassField(node) {
const identifier = node.key.name;
if (
typeof identifier !== 'undefined' &&
hasDanglingUnderscore(identifier) &&
enforceInClassFields &&
!isAllowed(identifier)
) {
context.report({
node,
messageId: 'unexpectedUnderscore',
data: {
identifier:
node.key.type === 'PrivateIdentifier' ?
`#${identifier}`
: identifier,
},
});
}
}
//--------------------------------------------------------------------------
// Public API
//--------------------------------------------------------------------------
return {
FunctionDeclaration: checkForDanglingUnderscoreInFunction,
VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
MemberExpression: checkForDanglingUnderscoreInMemberExpression,
MethodDefinition: checkForDanglingUnderscoreInMethod,
PropertyDefinition: checkForDanglingUnderscoreInClassField,
Property: checkForDanglingUnderscoreInMethod,
FunctionExpression: checkForDanglingUnderscoreInFunction,
ArrowFunctionExpression: checkForDanglingUnderscoreInFunction,
};
},
};