Repository: eslint/eslint
File: lib/rules/no-underscore-dangle.js (JavaScript)

Code before:
                context.report({
                    node,
                    messageId: "unexpectedUnderscore",
                    data: {
                        identifier
                    }
                });
            }
        }

        /**
         * Check if variable expression has a dangling underscore
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkForDanglingUnderscoreInVariableExpression(node) {
            const shouldDeepCheck = node && node.type && node.type === "VariableDeclarator" && node.id.type;

            if (shouldDeepCheck && node.id.type === "ArrayPattern" && Array.isArray(node.id.elements)) {
                node.id.elements.forEach(element => {
                    deepCheckDestructured(element, node.id.type);
                });
            }

            if (shouldDeepCheck && node.id?.type === "ObjectPattern" && Array.isArray(node.id.properties)) {
                node.id.properties.forEach(element => {
                    deepCheckDestructured(element, node.id.type);
                });
            }

            const identifier = node.id.name;

            if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
                !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
                context.report({
                    node,
                    messageId: "unexpectedUnderscore",
                    data: {
                        identifier
                    }
                });
            }
        }

        /**
         * Check if member expression has a dangling underscore
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */

Review comment (bug):
Tests on Node 12 are failing because of optional chaining syntax.

Same as the previous comment, `Array.isArray(node.id.properties)` seems unnecessary.

Code after:
                context.report({
                    node,
                    messageId: "unexpectedUnderscore",
                    data: {
                        identifier
                    }
                });
            }
        }

        /**
         * Check if variable expression has a dangling underscore
         * @param {ASTNode} node node to evaluate
         * @returns {void}
         * @private
         */
        function checkForDanglingUnderscoreInVariableExpression(node) {
            if (node.id.type === "ArrayPattern") {
                node.id.elements.forEach(element => {
                    deepCheckDestructured(element, node.id.type);
                });
            }

            if (node.id.type === "ObjectPattern") {
                node.id.properties.forEach(element => {
                    deepCheckDestructured(element, node.id.type);
                });
            }

            const identifier = node.id.name;

            if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
                !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
                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,