code:
/**
 * @fileoverview Rule to flag use of console object
 * @author Nicholas C. Zakas
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow the use of `console`",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-console"
        },

        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: {
                            type: "string"
                        },
                        minItems: 1,
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ],

        hasSuggestions: true,

        messages: {
            unexpected: "Unexpected console statement.",
            removeConsole: "Remove the console.{{ propertyName }}()."
        }
    },

    create(context) {
        const options = context.options[0] || {};
        const allowed = options.allow || [];
        const sourceCode = context.sourceCode;

        /**
         * Checks whether the given reference is 'console' or not.
         * @param {eslint-scope.Reference} reference The reference to check.
         * @returns {boolean} `true` if the reference is 'console'.
         */
        function isConsole(reference) {
            const id = reference.identifier;

            return id && id.name === "console";
        }

        /**
         * Checks whether the property name of the given MemberExpression node
         * is allowed by options or not.
         * @param {ASTNode} node The MemberExpression node to check.
         * @returns {boolean} `true` if the property name of the node is allowed.
         */
        function isAllowed(node) {
            const propertyName = astUtils.getStaticPropertyName(node);

            return propertyName && allowed.includes(propertyName);
        }

        /**
         * Checks whether the given reference is a member access which is not
         * allowed by options or not.
         * @param {eslint-scope.Reference} reference The reference to check.
         * @returns {boolean} `true` if the reference is a member access which
         *      is not allowed by options.
         */
        function isMemberAccessExceptAllowed(reference) {
            const node = reference.identifier;
            const parent = node.parent;

            return (
                parent.type === "MemberExpression" &&
                parent.object === node &&
                !isAllowed(parent)
            );
        }

        /**
         * Checks if removing the ExpressionStatement node will cause ASI to
         * break.
         * eg.
         * foo()
         * console.log();
         * [1, 2, 3].forEach(a => doSomething(a))
         *
         * Removing the console.log(); statement should leave two statements, but
         * here the two statements will become one because [ causes continuation after
         * foo().
         * @param {ASTNode} node The ExpressionStatement node to check.
         * @returns {boolean} `true` if ASI will break after removing the ExpressionStatement
         *      node.
         */
        function maybeAsiHazard(node) {
            const SAFE_TOKENS_BEFORE = /^[:;{]$/u; // One of :;{
            const UNSAFE_CHARS_AFTER = /^[-[(/+`]/u; // One of [(/+-`

            const tokenBefore = sourceCode.getTokenBefore(node);
            const tokenAfter = sourceCode.getTokenAfter(node);

            return (
                Boolean(tokenAfter) &&
                UNSAFE_CHARS_AFTER.test(tokenAfter.value) &&
                tokenAfter.value !== "++" &&
                tokenAfter.value !== "--" &&
                Boolean(tokenBefore) &&
                !SAFE_TOKENS_BEFORE.test(tokenBefore.value)
            );
        }

        /**
         * Checks if the MemberExpression node's parent.parent.parent is a
         * Program, BlockStatement, StaticBlock, or SwitchCase node. This check
         * is necessary to avoid providing a suggestion that might cause a syntax error.
         *
         * eg. if (a) console.log(b), removing console.log() here will lead to a
         *     syntax error.
         *     if (a) { console.log(b) }, removing console.log() here is acceptable.
         *
         * Additionally, it checks if the callee of the CallExpression node is
         * the node itself.
         *
         * eg. foo(console.log), cannot provide a suggestion here.
         * @param {ASTNode} node The MemberExpression node to check.
         * @returns {boolean} `true` if a suggestion can be provided for a node.
         */
        function canProvideSuggestions(node) {
            return (
                node.parent.type === "CallExpression" &&
                node.parent.callee === node &&
                node.parent.parent.type === "ExpressionStatement" &&
                astUtils.STATEMENT_LIST_PARENTS.has(node.parent.parent.parent.type) &&
                !maybeAsiHazard(node.parent.parent)
            );
        }

        /**
         * Reports the given reference as a violation.
         * @param {eslint-scope.Reference} reference The reference to report.
         * @returns {void}
         */
        function report(reference) {
            const node = reference.identifier.parent;

            const propertyName = astUtils.getStaticPropertyName(node);

            context.report({
                node,
                loc: node.loc,
                messageId: "unexpected",
                suggest: canProvideSuggestions(node)
                    ? [{
                        messageId: "removeConsole",
                        data: { propertyName },
                        fix(fixer) {
                            return fixer.remove(node.parent.parent);
                        }
                    }]
                    : []
            });
        }

        return {
            "Program:exit"(node) {
                const scope = sourceCode.getScope(node);
                const consoleVar = astUtils.getVariableByName(scope, "console");
                const shadowed = consoleVar && consoleVar.defs.length > 0;

                /*
                 * 'scope.through' includes all references to undefined
                 * variables. If the variable 'console' is not defined, it uses
                 * 'scope.through'.
                 */
                const references = consoleVar
                    ? consoleVar.references
                    : scope.through.filter(isConsole);

                if (!shadowed) {
                    references
                        .filter(isMemberAccessExceptAllowed)
                        .forEach(report);
                }
            }
        };
    }
};


code:
/**
 * @fileoverview A rule to disallow modifying variables that are declared using `const`
 * @author Toru Nagashima
 */

"use strict";

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow reassigning `const` variables",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-const-assign"
        },

        schema: [],

        messages: {
            const: "'{{name}}' is constant."
        }
    },

    create(context) {

        const sourceCode = context.sourceCode;

        /**
         * Finds and reports references that are non initializer and writable.
         * @param {Variable} variable A variable to check.
         * @returns {void}
         */
        function checkVariable(variable) {
            astUtils.getModifyingReferences(variable.references).forEach(reference => {
                context.report({ node: reference.identifier, messageId: "const", data: { name: reference.identifier.name } });
            });
        }

        return {
            VariableDeclaration(node) {
                if (node.kind === "const") {
                    sourceCode.getDeclaredVariables(node).forEach(checkVariable);
                }
            }
        };

    }
};

license: mit


code:
/**
 * @fileoverview Rule to flag constant comparisons and logical expressions that always/never short circuit
 * @author Jordan Eldredge <https://jordaneldredge.com>
 */

"use strict";

const globals = require("globals");
const { isNullLiteral, isConstant, isReferenceToGlobalVariable, isLogicalAssignmentOperator } = require("./utils/ast-utils");

const NUMERIC_OR_STRING_BINARY_OPERATORS = new Set(["+", "-", "*", "/", "%", "|", "^", "&", "**", "<<", ">>", ">>>"]);

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Checks whether or not a node is `null` or `undefined`. Similar to the one
 * found in ast-utils.js, but this one correctly handles the edge case that
 * `undefined` has been redefined.
 * @param {Scope} scope Scope in which the expression was found.
 * @param {ASTNode} node A node to check.
 * @returns {boolean} Whether or not the node is a `null` or `undefined`.
 * @public
 */
function isNullOrUndefined(scope, node) {
    return (
        isNullLiteral(node) ||
        (node.type === "Identifier" && node.name === "undefined" && isReferenceToGlobalVariable(scope, node)) ||
        (node.type === "UnaryExpression" && node.operator === "void")
    );
}

/**
 * Test if an AST node has a statically knowable constant nullishness. Meaning,
 * it will always resolve to a constant value of either: `null`, `undefined`
 * or not `null` _or_ `undefined`. An expression that can vary between those
 * three states at runtime would return `false`.
 * @param {Scope} scope The scope in which the node was found.
 * @param {ASTNode} node The AST node being tested.
 * @param {boolean} nonNullish if `true` then nullish values are not considered constant.
 * @returns {boolean} Does `node` have constant nullishness?
 */
function hasConstantNullishness(scope, node, nonNullish) {
    if (nonNullish && isNullOrUndefined(scope, node)) {
        return false;
    }

    switch (node.type) {
        case "ObjectExpression": // Objects are never nullish
        case "ArrayExpression": // Arrays are never nullish
        case "ArrowFunctionExpression": // Functions never nullish
        case "FunctionExpression": // Functions are never nullish
        case "ClassExpression": // Classes are never nullish
        case "NewExpression": // Objects are never nullish
        case "Literal": // Nullish, or non-nullish, literals never change
        case "TemplateLiteral": // A string is never nullish
        case "UpdateExpression": // Numbers are never nullish
        case "BinaryExpression": // Numbers, strings, or booleans are never nullish
            return true;
        case "CallExpression": {
            if (node.callee.type !== "Identifier") {
                return false;
            }
            const functionName = node.callee.name;

            return (functionName === "Boolean" || functionName === "String" || functionName === "Number") &&
                isReferenceToGlobalVariable(scope, node.callee);
        }
        case "LogicalExpression": {
            return node.operator === "??" && hasConstantNullishness(scope, node.right, true);
        }
        case "AssignmentExpression":
            if (node.operator === "=") {
                return hasConstantNullishness(scope, node.right, nonNullish);
            }

            /*
             * Handling short-circuiting assignment operators would require
             * walking the scope. We won't attempt that (for now...) /
             */
            if (isLogicalAssignmentOperator(node.operator)) {
                return false;
            }

            /*
             * The remaining assignment expressions all result in a numeric or
             * string (non-nullish) value:
             *   "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "|=", "^=", "&="
             */

            return true;
        case "UnaryExpression":

            /*
             * "void" Always returns `undefined`
             * "typeof" All types are strings, and thus non-nullish
             * "!" Boolean is never nullish
             * "delete" Returns a boolean, which is never nullish
             * Math operators always return numbers or strings, neither of which
             * are non-nullish "+", "-", "~"
             */

            return true;
        case "SequenceExpression": {
            const last = node.expressions[node.expressions.length - 1];

            return hasConstantNullishness(scope, last, nonNullish);
        }
        case "Identifier":
            return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
        case "JSXElement": // ESLint has a policy of not assuming any specific JSX behavior.
        case "JSXFragment":
            return false;
        default:
            return false;
    }
}

/**
 * Test if an AST node is a boolean value that never changes. Specifically we
 * test for:
 * 1. Literal booleans (`true` or `false`)
 * 2. Unary `!` expressions with a constant value
 * 3. Constant booleans created via the `Boolean` global function
 * @param {Scope} scope The scope in which the node was found.
 * @param {ASTNode} node The node to test
 * @returns {boolean} Is `node` guaranteed to be a boolean?
 */
function isStaticBoolean(scope, node) {
    switch (node.type) {
        case "Literal":
            return typeof node.value === "boolean";
        case "CallExpression":
            return node.callee.type === "Identifier" && node.callee.name === "Boolean" &&
              isReferenceToGlobalVariable(scope, node.callee) &&
              (node.arguments.length === 0 || isConstant(scope, node.arguments[0], true));
        case "UnaryExpression":
            return node.operator === "!" && isConstant(scope, node.argument, true);
        default:
            return false;
    }
}

/**
 * Test if an AST node will always give the same result when compared to a
 * boolean value. Note that comparison to boolean values is different than
 * truthiness.
 * https://262.ecma-international.org/5.1/#sec-11.9.3
 *
 * Javascript `==` operator works by converting the boolean to `1` (true) or
 * `+0` (false) and then checks the values `==` equality to that number.
 * @param {Scope} scope The scope in which node was found.
 * @param {ASTNode} node The node to test.
 * @returns {boolean} Will `node` always coerce to the same boolean value?
 */
function hasConstantLooseBooleanComparison(scope, node) {
    switch (node.type) {
        case "ObjectExpression":
        case "ClassExpression":

            /**
             * In theory objects like:
             *
             * `{toString: () => a}`
             * `{valueOf: () => a}`
             *
             * Or a classes like:
             *
             * `class { static toString() { return a } }`
             * `class { static valueOf() { return a } }`
             *
             * Are not constant verifiably when `inBooleanPosition` is
             * false, but it's an edge case we've opted not to handle.
             */
            return true;
        case "ArrayExpression": {
            const nonSpreadElements = node.elements.filter(e =>

                // Elements can be `null` in sparse arrays: `[,,]`;
                e !== null && e.type !== "SpreadElement");

            /*
             * Possible future direction if needed: We could check if the
             * single value would result in variable boolean comparison.
             * For now we will err on the side of caution since `[x]` could
             * evaluate to `[0]` or `[1]`.
             */
            return node.elements.length === 0 || nonSpreadElements.length > 1;
        }
        case "ArrowFunctionExpression":
        case "FunctionExpression":
            return true;
        case "UnaryExpression":
            if (node.operator === "void" || // Always returns `undefined`
                node.operator === "typeof" // All `typeof` strings, when coerced to number, are not 0 or 1.
            ) {
                return true;
            }
            if (node.operator === "!") {
                return isConstant(scope, node.argument, true);
            }

            /*
             * We won't try to reason about +, -, ~, or delete
             * In theory, for the mathematical operators, we could look at the
             * argument and try to determine if it coerces to a constant numeric
             * value.
             */
            return false;
        case "NewExpression": // Objects might have custom `.valueOf` or `.toString`.
            return false;
        case "CallExpression": {
            if (node.callee.type === "Identifier" &&
                node.callee.name === "Boolean" &&
                isReferenceToGlobalVariable(scope, node.callee)
            ) {
                return node.arguments.length === 0 || isConstant(scope, node.arguments[0], true);
            }
            return false;
        }
        case "Literal": // True or false, literals never change
            return true;
        case "Identifier":
            return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
        case "TemplateLiteral":

            /*
             * In theory we could try to check if the quasi are sufficient to
             * prove that the expression will always be true, but it would be
             * tricky to get right. For example: `000.${foo}000`
             */
            return node.expressions.length === 0;
        case "AssignmentExpression":
            if (node.operator === "=") {
                return hasConstantLooseBooleanComparison(scope, node.right);
            }

            /*
             * Handling short-circuiting assignment operators would require
             * walking the scope. We won't attempt that (for now...)
             *
             * The remaining assignment expressions all result in a numeric or
             * string (non-nullish) values which could be truthy or falsy:
             *   "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "|=", "^=", "&="
             */
            return false;
        case "SequenceExpression": {
            const last = node.expressions[node.expressions.length - 1];

            return hasConstantLooseBooleanComparison(scope, last);
        }
        case "JSXElement": // ESLint has a policy of not assuming any specific JSX behavior.
        case "JSXFragment":
            return false;
        default:
            return false;
    }
}

/**
 * Test if an AST node will always give the same result when _strictly_ compared
 * to a boolean value. This can happen if the expression can never be boolean, or
 * if it is always the same boolean value.
 * @param {Scope} scope The scope in which the node was found.
 * @param {ASTNode} node The node to test
 * @returns {boolean} Will `node` always give the same result when compared to a
 * static boolean value?
 */
function hasConstantStrictBooleanComparison(scope, node) {
    switch (node.type) {
        case "ObjectExpression": // Objects are not booleans
        case "ArrayExpression": // Arrays are not booleans
        case "ArrowFunctionExpression": // Functions are not booleans
        case "FunctionExpression":
        case "ClassExpression": // Classes are not booleans
        case "NewExpression": // Objects are not booleans
        case "TemplateLiteral": // Strings are not booleans
        case "Literal": // True, false, or not boolean, literals never change.
        case "UpdateExpression": // Numbers are not booleans
            return true;
        case "BinaryExpression":
            return NUMERIC_OR_STRING_BINARY_OPERATORS.has(node.operator);
        case "UnaryExpression": {
            if (node.operator === "delete") {
                return false;
            }
            if (node.operator === "!") {
                return isConstant(scope, node.argument, true);
            }

            /*
             * The remaining operators return either strings or numbers, neither
             * of which are boolean.
             */
            return true;
        }
        case "SequenceExpression": {
            const last = node.expressions[node.expressions.length - 1];

            return hasConstantStrictBooleanComparison(scope, last);
        }
        case "Identifier":
            return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
        case "AssignmentExpression":
            if (node.operator === "=") {
                return hasConstantStrictBooleanComparison(scope, node.right);
            }

            /*
             * Handling short-circuiting assignment operators would require
             * walking the scope. We won't attempt that (for now...)
             */
            if (isLogicalAssignmentOperator(node.operator)) {
                return false;
            }

            /*
             * The remaining assignment expressions all result in either a number
             * or a string, neither of which can ever be boolean.
             */
            return true;
        case "CallExpression": {
            if (node.callee.type !== "Identifier") {
                return false;
            }
            const functionName = node.callee.name;

            if (
                (functionName === "String" || functionName === "Number") &&
                isReferenceToGlobalVariable(scope, node.callee)
            ) {
                return true;
            }
            if (functionName === "Boolean" && isReferenceToGlobalVariable(scope, node.callee)) {
                return (
                    node.arguments.length === 0 || isConstant(scope, node.arguments[0], true));
            }
            return false;
        }
        case "JSXElement": // ESLint has a policy of not assuming any specific JSX behavior.
        case "JSXFragment":
            return false;
        default:
            return false;
    }
}

/**
 * Test if an AST node will always result in a newly constructed object
 * @param {Scope} scope The scope in which the node was found.
 * @param {ASTNode} node The node to test
 * @returns {boolean} Will `node` always be new?
 */
function isAlwaysNew(scope, node) {
    switch (node.type) {
        case "ObjectExpression":
        case "ArrayExpression":
        case "ArrowFunctionExpression":
        case "FunctionExpression":
        case "ClassExpression":
            return true;
        case "NewExpression": {
            if (node.callee.type !== "Identifier") {
                return false;
            }

            /*
             * All the built-in constructors are always new, but
             * user-defined constructors could return a sentinel
             * object.
             *
             * Catching these is especially useful for primitive constructors
             * which return boxed values, a surprising gotcha' in JavaScript.
             */
            return Object.hasOwnProperty.call(globals.builtin, node.callee.name) &&
              isReferenceToGlobalVariable(scope, node.callee);
        }
        case "Literal":

            // Regular expressions are objects, and thus always new
            return typeof node.regex === "object";
        case "SequenceExpression": {
            const last = node.expressions[node.expressions.length - 1];

            return isAlwaysNew(scope, last);
        }
        case "AssignmentExpression":
            if (node.operator === "=") {
                return isAlwaysNew(scope, node.right);
            }
            return false;
        case "ConditionalExpression":
            return isAlwaysNew(scope, node.consequent) && isAlwaysNew(scope, node.alternate);
        case "JSXElement": // ESLint has a policy of not assuming any specific JSX behavior.
        case "JSXFragment":
            return false;
        default:
            return false;
    }
}

/**
 * Checks if one operand will cause the result to be constant.
 * @param {Scope} scope Scope in which the expression was found.
 * @param {ASTNode} a One side of the expression
 * @param {ASTNode} b The other side of the expression
 * @param {string} operator The binary expression operator
 * @returns {ASTNode | null} The node which will cause the expression to have a constant result.
 */
function findBinaryExpressionConstantOperand(scope, a, b, operator) {
    if (operator === "==" || operator === "!=") {
        if (
            (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
            (isStaticBoolean(scope, a) && hasConstantLooseBooleanComparison(scope, b))
        ) {
            return b;
        }
    } else if (operator === "===" || operator === "!==") {
        if (
            (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
            (isStaticBoolean(scope, a) && hasConstantStrictBooleanComparison(scope, b))
        ) {
            return b;
        }
    }
    return null;
}

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",
        docs: {
            description: "Disallow expressions where the operation doesn't affect the value",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-constant-binary-expression"
        },
        schema: [],
        messages: {
            constantBinaryOperand: "Unexpected constant binary expression. Compares constantly with the {{otherSide}}-hand side of the `{{operator}}`.",
            constantShortCircuit: "Unexpected constant {{property}} on the left-hand side of a `{{operator}}` expression.",
            alwaysNew: "Unexpected comparison to newly constructed object. These two values can never be equal.",
            bothAlwaysNew: "Unexpected comparison of two newly constructed objects. These two values can never be equal."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;

        return {
            LogicalExpression(node) {
                const { operator, left } = node;
                const scope = sourceCode.getScope(node);

                if ((operator === "&&" || operator === "||") && isConstant(scope, left, true)) {
                    context.report({ node: left, messageId: "constantShortCircuit", data: { property: "truthiness", operator } });
                } else if (operator === "??" && hasConstantNullishness(scope, left, false)) {
                    context.report({ node: left, messageId: "constantShortCircuit", data: { property: "nullishness", operator } });
                }
            },
            BinaryExpression(node) {
                const scope = sourceCode.getScope(node);
                const { right, left, operator } = node;
                const rightConstantOperand = findBinaryExpressionConstantOperand(scope, left, right, operator);
                const leftConstantOperand = findBinaryExpressionConstantOperand(scope, right, left, operator);

                if (rightConstantOperand) {
                    context.report({ node: rightConstantOperand, messageId: "constantBinaryOperand", data: { operator, otherSide: "left" } });
                } else if (leftConstantOperand) {
                    context.report({ node: leftConstantOperand, messageId: "constantBinaryOperand", data: { operator, otherSide: "right" } });
                } else if (operator === "===" || operator === "!==") {
                    if (isAlwaysNew(scope, left)) {
                        context.report({ node: left, messageId: "alwaysNew" });
                    } else if (isAlwaysNew(scope, right)) {
                        context.report({ node: right, messageId: "alwaysNew" });
                    }
                } else if (operator === "==" || operator === "!=") {

                    /*
                     * If both sides are "new", then both sides are objects and
                     * therefore they will be compared by reference even with `==`
                     * equality.
                     */
                    if (isAlwaysNew(scope, left) && isAlwaysNew(scope, right)) {
                        context.report({ node: left, messageId: "bothAlwaysNew" });
                    }
                }

            }

            /*
             * In theory we could handle short-circuiting assignment operators,
             * for some constant values, but that would require walking the
             * scope to find the value of the variable being assigned. This is
             * dependant on https://github.com/eslint/eslint/issues/13776
             *
             * AssignmentExpression() {},
             */
        };
    }
};


code:
/**
 * @fileoverview Rule to flag use constant conditions
 * @author Christian Schulz <http://rndm.de>
 */

"use strict";

const { isConstant } = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow constant expressions in conditions",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-constant-condition"
        },

        schema: [
            {
                type: "object",
                properties: {
                    checkLoops: {
                        type: "boolean",
                        default: true
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            unexpected: "Unexpected constant condition."
        }
    },

    create(context) {
        const options = context.options[0] || {},
            checkLoops = options.checkLoops !== false,
            loopSetStack = [];
        const sourceCode = context.sourceCode;

        let loopsInCurrentScope = new Set();

        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------

        /**
         * Tracks when the given node contains a constant condition.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function trackConstantConditionLoop(node) {
            if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
                loopsInCurrentScope.add(node);
            }
        }

        /**
         * Reports when the set contains the given constant condition node
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkConstantConditionLoopInSet(node) {
            if (loopsInCurrentScope.has(node)) {
                loopsInCurrentScope.delete(node);
                context.report({ node: node.test, messageId: "unexpected" });
            }
        }

        /**
         * Reports when the given node contains a constant condition.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function reportIfConstant(node) {
            if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
                context.report({ node: node.test, messageId: "unexpected" });
            }
        }

        /**
         * Stores current set of constant loops in loopSetStack temporarily
         * and uses a new set to track constant loops
         * @returns {void}
         * @private
         */
        function enterFunction() {
            loopSetStack.push(loopsInCurrentScope);
            loopsInCurrentScope = new Set();
        }

        /**
         * Reports when the set still contains stored constant conditions
         * @returns {void}
         * @private
         */
        function exitFunction() {
            loopsInCurrentScope = loopSetStack.pop();
        }

        /**
         * Checks node when checkLoops option is enabled
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkLoop(node) {
            if (checkLoops) {
                trackConstantConditionLoop(node);
            }
        }

        //--------------------------------------------------------------------------
        // Public
        //--------------------------------------------------------------------------

        return {
            ConditionalExpression: reportIfConstant,
            IfStatement: reportIfConstant,
            WhileStatement: checkLoop,
            "WhileStatement:exit": checkConstantConditionLoopInSet,
            DoWhileStatement: checkLoop,
            "DoWhileStatement:exit": checkConstantConditionLoopInSet,
            ForStatement: checkLoop,
            "ForStatement > .test": node => checkLoop(node.parent),
            "ForStatement:exit": checkConstantConditionLoopInSet,
            FunctionDeclaration: enterFunction,
            "FunctionDeclaration:exit": exitFunction,
            FunctionExpression: enterFunction,
            "FunctionExpression:exit": exitFunction,
            YieldExpression: () => loopsInCurrentScope.clear()
        };

    }
};


code:
/**
 * @fileoverview Rule to disallow returning value from constructor.
 * @author Pig Fang <https://github.com/g-plane>
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow returning value from constructor",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-constructor-return"
        },

        schema: {},

        fixable: null,

        messages: {
            unexpected: "Unexpected return statement in constructor."
        }
    },

    create(context) {
        const stack = [];

        return {
            onCodePathStart(_, node) {
                stack.push(node);
            },
            onCodePathEnd() {
                stack.pop();
            },
            ReturnStatement(node) {
                const last = stack[stack.length - 1];

                if (!last.parent) {
                    return;
                }

                if (
                    last.parent.type === "MethodDefinition" &&
                    last.parent.kind === "constructor" &&
                    (node.parent.parent === last || node.argument)
                ) {
                    context.report({
                        node,
                        messageId: "unexpected"
                    });
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to flag use of continue statement
 * @author Borislav Zhivkov
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow `continue` statements",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-continue"
        },

        schema: [],

        messages: {
            unexpected: "Unexpected use of continue statement."
        }
    },

    create(context) {

        return {
            ContinueStatement(node) {
                context.report({ node, messageId: "unexpected" });
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to forbid control characters from regular expressions.
 * @author Nicholas C. Zakas
 */

"use strict";

const RegExpValidator = require("@eslint-community/regexpp").RegExpValidator;
const collector = new (class {
    constructor() {
        this._source = "";
        this._controlChars = [];
        this._validator = new RegExpValidator(this);
    }

    onPatternEnter() {

        /*
         * `RegExpValidator` may parse the pattern twice in one `validatePattern`.
         * So `this._controlChars` should be cleared here as well.
         *
         * For example, the `/(?<a>\x1f)/` regex will parse the pattern twice.
         * This is based on the content described in Annex B.
         * If the regex contains a `GroupName` and the `u` flag is not used, `ParseText` will be called twice.
         * See https://tc39.es/ecma262/2023/multipage/additional-ecmascript-features-for-web-browsers.html#sec-parsepattern-annexb
         */
        this._controlChars = [];
    }

    onCharacter(start, end, cp) {
        if (cp >= 0x00 &&
            cp <= 0x1F &&
            (
                this._source.codePointAt(start) === cp ||
                this._source.slice(start, end).startsWith("\\x") ||
                this._source.slice(start, end).startsWith("\\u")
            )
        ) {
            this._controlChars.push(`\\x${`0${cp.toString(16)}`.slice(-2)}`);
        }
    }

    collectControlChars(regexpStr, flags) {
        const uFlag = typeof flags === "string" && flags.includes("u");
        const vFlag = typeof flags === "string" && flags.includes("v");

        this._controlChars = [];
        this._source = regexpStr;

        try {
            this._validator.validatePattern(regexpStr, void 0, void 0, { unicode: uFlag, unicodeSets: vFlag }); // Call onCharacter hook
        } catch {

            // Ignore syntax errors in RegExp.
        }
        return this._controlChars;
    }
})();

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow control characters in regular expressions",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-control-regex"
        },

        schema: [],

        messages: {
            unexpected: "Unexpected control character(s) in regular expression: {{controlChars}}."
        }
    },

    create(context) {

        /**
         * Get the regex expression
         * @param {ASTNode} node `Literal` node to evaluate
         * @returns {{ pattern: string, flags: string | null } | null} Regex if found (the given node is either a regex literal
         * or a string literal that is the pattern argument of a RegExp constructor call). Otherwise `null`. If flags cannot be determined,
         * the `flags` property will be `null`.
         * @private
         */
        function getRegExp(node) {
            if (node.regex) {
                return node.regex;
            }
            if (typeof node.value === "string" &&
                (node.parent.type === "NewExpression" || node.parent.type === "CallExpression") &&
                node.parent.callee.type === "Identifier" &&
                node.parent.callee.name === "RegExp" &&
                node.parent.arguments[0] === node
            ) {
                const pattern = node.value;
                const flags =
                    node.parent.arguments.length > 1 &&
                    node.parent.arguments[1].type === "Literal" &&
                    typeof node.parent.arguments[1].value === "string"
                        ? node.parent.arguments[1].value
                        : null;

                return { pattern, flags };
            }

            return null;
        }

        return {
            Literal(node) {
                const regExp = getRegExp(node);

                if (regExp) {
                    const { pattern, flags } = regExp;
                    const controlCharacters = collector.collectControlChars(pattern, flags);

                    if (controlCharacters.length > 0) {
                        context.report({
                            node,
                            messageId: "unexpected",
                            data: {
                                controlChars: controlCharacters.join(", ")
                            }
                        });
                    }
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to flag use of a debugger statement
 * @author Nicholas C. Zakas
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow the use of `debugger`",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-debugger"
        },

        fixable: null,
        schema: [],

        messages: {
            unexpected: "Unexpected 'debugger' statement."
        }
    },

    create(context) {

        return {
            DebuggerStatement(node) {
                context.report({
                    node,
                    messageId: "unexpected"
                });
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to flag when deleting variables
 * @author Ilya Volodin
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow deleting variables",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-delete-var"
        },

        schema: [],

        messages: {
            unexpected: "Variables should not be deleted."
        }
    },

    create(context) {

        return {

            UnaryExpression(node) {
                if (node.operator === "delete" && node.argument.type === "Identifier") {
                    context.report({ node, messageId: "unexpected" });
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to check for ambiguous div operator in regexes
 * @author Matt DuVall <http://www.mattduvall.com>
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow equal signs explicitly at the beginning of regular expressions",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-div-regex"
        },

        fixable: "code",

        schema: [],

        messages: {
            unexpected: "A regular expression literal can be confused with '/='."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;

        return {

            Literal(node) {
                const token = sourceCode.getFirstToken(node);

                if (token.type === "RegularExpression" && token.value[1] === "=") {
                    context.report({
                        node,
                        messageId: "unexpected",
                        fix(fixer) {
                            return fixer.replaceTextRange([token.range[0] + 1, token.range[0] + 2], "[=]");
                        }
                    });
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to flag duplicate arguments
 * @author Jamund Ferguson
 */

"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate arguments in `function` definitions",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-dupe-args"
        },

        schema: [],

        messages: {
            unexpected: "Duplicate param '{{name}}'."
        }
    },

    create(context) {

        const sourceCode = context.sourceCode;

        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------

        /**
         * Checks whether or not a given definition is a parameter's.
         * @param {eslint-scope.DefEntry} def A definition to check.
         * @returns {boolean} `true` if the definition is a parameter's.
         */
        function isParameter(def) {
            return def.type === "Parameter";
        }

        /**
         * Determines if a given node has duplicate parameters.
         * @param {ASTNode} node The node to check.
         * @returns {void}
         * @private
         */
        function checkParams(node) {
            const variables = sourceCode.getDeclaredVariables(node);

            for (let i = 0; i < variables.length; ++i) {
                const variable = variables[i];

                // Checks and reports duplications.
                const defs = variable.defs.filter(isParameter);

                if (defs.length >= 2) {
                    context.report({
                        node,
                        messageId: "unexpected",
                        data: { name: variable.name }
                    });
                }
            }
        }

        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------

        return {
            FunctionDeclaration: checkParams,
            FunctionExpression: checkParams
        };

    }
};


code:
/**
 * @fileoverview A rule to disallow duplicate name in class members.
 * @author Toru Nagashima
 */

"use strict";

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate class members",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-dupe-class-members"
        },

        schema: [],

        messages: {
            unexpected: "Duplicate name '{{name}}'."
        }
    },

    create(context) {
        let stack = [];

        /**
         * Gets state of a given member name.
         * @param {string} name A name of a member.
         * @param {boolean} isStatic A flag which specifies that is a static member.
         * @returns {Object} A state of a given member name.
         *   - retv.init {boolean} A flag which shows the name is declared as normal member.
         *   - retv.get {boolean} A flag which shows the name is declared as getter.
         *   - retv.set {boolean} A flag which shows the name is declared as setter.
         */
        function getState(name, isStatic) {
            const stateMap = stack[stack.length - 1];
            const key = `$${name}`; // to avoid "__proto__".

            if (!stateMap[key]) {
                stateMap[key] = {
                    nonStatic: { init: false, get: false, set: false },
                    static: { init: false, get: false, set: false }
                };
            }

            return stateMap[key][isStatic ? "static" : "nonStatic"];
        }

        return {

            // Initializes the stack of state of member declarations.
            Program() {
                stack = [];
            },

            // Initializes state of member declarations for the class.
            ClassBody() {
                stack.push(Object.create(null));
            },

            // Disposes the state for the class.
            "ClassBody:exit"() {
                stack.pop();
            },

            // Reports the node if its name has been declared already.
            "MethodDefinition, PropertyDefinition"(node) {
                const name = astUtils.getStaticPropertyName(node);
                const kind = node.type === "MethodDefinition" ? node.kind : "field";

                if (name === null || kind === "constructor") {
                    return;
                }

                const state = getState(name, node.static);
                let isDuplicate = false;

                if (kind === "get") {
                    isDuplicate = (state.init || state.get);
                    state.get = true;
                } else if (kind === "set") {
                    isDuplicate = (state.init || state.set);
                    state.set = true;
                } else {
                    isDuplicate = (state.init || state.get || state.set);
                    state.init = true;
                }

                if (isDuplicate) {
                    context.report({ node, messageId: "unexpected", data: { name } });
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to disallow duplicate conditions in if-else-if chains
 * @author Milos Djermanovic
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
 * Determines whether the first given array is a subset of the second given array.
 * @param {Function} comparator A function to compare two elements, should return `true` if they are equal.
 * @param {Array} arrA The array to compare from.
 * @param {Array} arrB The array to compare against.
 * @returns {boolean} `true` if the array `arrA` is a subset of the array `arrB`.
 */
function isSubsetByComparator(comparator, arrA, arrB) {
    return arrA.every(a => arrB.some(b => comparator(a, b)));
}

/**
 * Splits the given node by the given logical operator.
 * @param {string} operator Logical operator `||` or `&&`.
 * @param {ASTNode} node The node to split.
 * @returns {ASTNode[]} Array of conditions that makes the node when joined by the operator.
 */
function splitByLogicalOperator(operator, node) {
    if (node.type === "LogicalExpression" && node.operator === operator) {
        return [...splitByLogicalOperator(operator, node.left), ...splitByLogicalOperator(operator, node.right)];
    }
    return [node];
}

const splitByOr = splitByLogicalOperator.bind(null, "||");
const splitByAnd = splitByLogicalOperator.bind(null, "&&");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate conditions in if-else-if chains",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-dupe-else-if"
        },

        schema: [],

        messages: {
            unexpected: "This branch can never execute. Its condition is a duplicate or covered by previous conditions in the if-else-if chain."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;

        /**
         * Determines whether the two given nodes are considered to be equal. In particular, given that the nodes
         * represent expressions in a boolean context, `||` and `&&` can be considered as commutative operators.
         * @param {ASTNode} a First node.
         * @param {ASTNode} b Second node.
         * @returns {boolean} `true` if the nodes are considered to be equal.
         */
        function equal(a, b) {
            if (a.type !== b.type) {
                return false;
            }

            if (
                a.type === "LogicalExpression" &&
                (a.operator === "||" || a.operator === "&&") &&
                a.operator === b.operator
            ) {
                return equal(a.left, b.left) && equal(a.right, b.right) ||
                    equal(a.left, b.right) && equal(a.right, b.left);
            }

            return astUtils.equalTokens(a, b, sourceCode);
        }

        const isSubset = isSubsetByComparator.bind(null, equal);

        return {
            IfStatement(node) {
                const test = node.test,
                    conditionsToCheck = test.type === "LogicalExpression" && test.operator === "&&"
                        ? [test, ...splitByAnd(test)]
                        : [test];
                let current = node,
                    listToCheck = conditionsToCheck.map(c => splitByOr(c).map(splitByAnd));

                while (current.parent && current.parent.type === "IfStatement" && current.parent.alternate === current) {
                    current = current.parent;

                    const currentOrOperands = splitByOr(current.test).map(splitByAnd);

                    listToCheck = listToCheck.map(orOperands => orOperands.filter(
                        orOperand => !currentOrOperands.some(currentOrOperand => isSubset(currentOrOperand, orOperand))
                    ));

                    if (listToCheck.some(orOperands => orOperands.length === 0)) {
                        context.report({ node: test, messageId: "unexpected" });
                        break;
                    }
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to flag use of duplicate keys in an object.
 * @author Ian Christian Myers
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const GET_KIND = /^(?:init|get)$/u;
const SET_KIND = /^(?:init|set)$/u;

/**
 * The class which stores properties' information of an object.
 */
class ObjectInfo {

    /**
     * @param {ObjectInfo|null} upper The information of the outer object.
     * @param {ASTNode} node The ObjectExpression node of this information.
     */
    constructor(upper, node) {
        this.upper = upper;
        this.node = node;
        this.properties = new Map();
    }

    /**
     * Gets the information of the given Property node.
     * @param {ASTNode} node The Property node to get.
     * @returns {{get: boolean, set: boolean}} The information of the property.
     */
    getPropertyInfo(node) {
        const name = astUtils.getStaticPropertyName(node);

        if (!this.properties.has(name)) {
            this.properties.set(name, { get: false, set: false });
        }
        return this.properties.get(name);
    }

    /**
     * Checks whether the given property has been defined already or not.
     * @param {ASTNode} node The Property node to check.
     * @returns {boolean} `true` if the property has been defined.
     */
    isPropertyDefined(node) {
        const entry = this.getPropertyInfo(node);

        return (
            (GET_KIND.test(node.kind) && entry.get) ||
            (SET_KIND.test(node.kind) && entry.set)
        );
    }

    /**
     * Defines the given property.
     * @param {ASTNode} node The Property node to define.
     * @returns {void}
     */
    defineProperty(node) {
        const entry = this.getPropertyInfo(node);

        if (GET_KIND.test(node.kind)) {
            entry.get = true;
        }
        if (SET_KIND.test(node.kind)) {
            entry.set = true;
        }
    }
}

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate keys in object literals",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-dupe-keys"
        },

        schema: [],

        messages: {
            unexpected: "Duplicate key '{{name}}'."
        }
    },

    create(context) {
        let info = null;

        return {
            ObjectExpression(node) {
                info = new ObjectInfo(info, node);
            },
            "ObjectExpression:exit"() {
                info = info.upper;
            },

            Property(node) {
                const name = astUtils.getStaticPropertyName(node);

                // Skip destructuring.
                if (node.parent.type !== "ObjectExpression") {
                    return;
                }

                // Skip if the name is not static.
                if (name === null) {
                    return;
                }

                // Reports if the name is defined already.
                if (info.isPropertyDefined(node)) {
                    context.report({
                        node: info.node,
                        loc: node.key.loc,
                        messageId: "unexpected",
                        data: { name }
                    });
                }

                // Update info.
                info.defineProperty(node);
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to disallow a duplicate case label.
 * @author Dieter Oberkofler
 * @author Burak Yigit Kaya
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate case labels",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-duplicate-case"
        },

        schema: [],

        messages: {
            unexpected: "Duplicate case label."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;

        /**
         * Determines whether the two given nodes are considered to be equal.
         * @param {ASTNode} a First node.
         * @param {ASTNode} b Second node.
         * @returns {boolean} `true` if the nodes are considered to be equal.
         */
        function equal(a, b) {
            if (a.type !== b.type) {
                return false;
            }

            return astUtils.equalTokens(a, b, sourceCode);
        }
        return {
            SwitchStatement(node) {
                const previousTests = [];

                for (const switchCase of node.cases) {
                    if (switchCase.test) {
                        const test = switchCase.test;

                        if (previousTests.some(previousTest => equal(previousTest, test))) {
                            context.report({ node: switchCase, messageId: "unexpected" });
                        } else {
                            previousTests.push(test);
                        }
                    }
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Restrict usage of duplicate imports.
 * @author Simen Bekkhus
 */
"use strict";

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const NAMED_TYPES = ["ImportSpecifier", "ExportSpecifier"];
const NAMESPACE_TYPES = [
    "ImportNamespaceSpecifier",
    "ExportNamespaceSpecifier"
];

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/**
 * Check if an import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier).
 * @param {string} importExportType An import/export type to check.
 * @param {string} type Can be "named" or "namespace"
 * @returns {boolean} True if import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier) and false if it doesn't.
 */
function isImportExportSpecifier(importExportType, type) {
    const arrayToCheck = type === "named" ? NAMED_TYPES : NAMESPACE_TYPES;

    return arrayToCheck.includes(importExportType);
}

/**
 * Return the type of (import|export).
 * @param {ASTNode} node A node to get.
 * @returns {string} The type of the (import|export).
 */
function getImportExportType(node) {
    if (node.specifiers && node.specifiers.length > 0) {
        const nodeSpecifiers = node.specifiers;
        const index = nodeSpecifiers.findIndex(
            ({ type }) =>
                isImportExportSpecifier(type, "named") ||
                isImportExportSpecifier(type, "namespace")
        );
        const i = index > -1 ? index : 0;

        return nodeSpecifiers[i].type;
    }
    if (node.type === "ExportAllDeclaration") {
        if (node.exported) {
            return "ExportNamespaceSpecifier";
        }
        return "ExportAll";
    }
    return "SideEffectImport";
}

/**
 * Returns a boolean indicates if two (import|export) can be merged
 * @param {ASTNode} node1 A node to check.
 * @param {ASTNode} node2 A node to check.
 * @returns {boolean} True if two (import|export) can be merged, false if they can't.
 */
function isImportExportCanBeMerged(node1, node2) {
    const importExportType1 = getImportExportType(node1);
    const importExportType2 = getImportExportType(node2);

    if (
        (importExportType1 === "ExportAll" &&
            importExportType2 !== "ExportAll" &&
            importExportType2 !== "SideEffectImport") ||
        (importExportType1 !== "ExportAll" &&
            importExportType1 !== "SideEffectImport" &&
            importExportType2 === "ExportAll")
    ) {
        return false;
    }
    if (
        (isImportExportSpecifier(importExportType1, "namespace") &&
            isImportExportSpecifier(importExportType2, "named")) ||
        (isImportExportSpecifier(importExportType2, "namespace") &&
            isImportExportSpecifier(importExportType1, "named"))
    ) {
        return false;
    }
    return true;
}

/**
 * Returns a boolean if we should report (import|export).
 * @param {ASTNode} node A node to be reported or not.
 * @param {[ASTNode]} previousNodes An array contains previous nodes of the module imported or exported.
 * @returns {boolean} True if the (import|export) should be reported.
 */
function shouldReportImportExport(node, previousNodes) {
    let i = 0;

    while (i < previousNodes.length) {
        if (isImportExportCanBeMerged(node, previousNodes[i])) {
            return true;
        }
        i++;
    }
    return false;
}

/**
 * Returns array contains only nodes with declarations types equal to type.
 * @param {[{node: ASTNode, declarationType: string}]} nodes An array contains objects, each object contains a node and a declaration type.
 * @param {string} type Declaration type.
 * @returns {[ASTNode]} An array contains only nodes with declarations types equal to type.
 */
function getNodesByDeclarationType(nodes, type) {
    return nodes
        .filter(({ declarationType }) => declarationType === type)
        .map(({ node }) => node);
}

/**
 * Returns the name of the module imported or re-exported.
 * @param {ASTNode} node A node to get.
 * @returns {string} The name of the module, or empty string if no name.
 */
function getModule(node) {
    if (node && node.source && node.source.value) {
        return node.source.value.trim();
    }
    return "";
}

/**
 * Checks if the (import|export) can be merged with at least one import or one export, and reports if so.
 * @param {RuleContext} context The ESLint rule context object.
 * @param {ASTNode} node A node to get.
 * @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
 * @param {string} declarationType A declaration type can be an import or export.
 * @param {boolean} includeExports Whether or not to check for exports in addition to imports.
 * @returns {void} No return value.
 */
function checkAndReport(
    context,
    node,
    modules,
    declarationType,
    includeExports
) {
    const module = getModule(node);

    if (modules.has(module)) {
        const previousNodes = modules.get(module);
        const messagesIds = [];
        const importNodes = getNodesByDeclarationType(previousNodes, "import");
        let exportNodes;

        if (includeExports) {
            exportNodes = getNodesByDeclarationType(previousNodes, "export");
        }
        if (declarationType === "import") {
            if (shouldReportImportExport(node, importNodes)) {
                messagesIds.push("import");
            }
            if (includeExports) {
                if (shouldReportImportExport(node, exportNodes)) {
                    messagesIds.push("importAs");
                }
            }
        } else if (declarationType === "export") {
            if (shouldReportImportExport(node, exportNodes)) {
                messagesIds.push("export");
            }
            if (shouldReportImportExport(node, importNodes)) {
                messagesIds.push("exportAs");
            }
        }
        messagesIds.forEach(messageId =>
            context.report({
                node,
                messageId,
                data: {
                    module
                }
            }));
    }
}

/**
 * @callback nodeCallback
 * @param {ASTNode} node A node to handle.
 */

/**
 * Returns a function handling the (imports|exports) of a given file
 * @param {RuleContext} context The ESLint rule context object.
 * @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
 * @param {string} declarationType A declaration type can be an import or export.
 * @param {boolean} includeExports Whether or not to check for exports in addition to imports.
 * @returns {nodeCallback} A function passed to ESLint to handle the statement.
 */
function handleImportsExports(
    context,
    modules,
    declarationType,
    includeExports
) {
    return function(node) {
        const module = getModule(node);

        if (module) {
            checkAndReport(
                context,
                node,
                modules,
                declarationType,
                includeExports
            );
            const currentNode = { node, declarationType };
            let nodes = [currentNode];

            if (modules.has(module)) {
                const previousNodes = modules.get(module);

                nodes = [...previousNodes, currentNode];
            }
            modules.set(module, nodes);
        }
    };
}

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow duplicate module imports",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-duplicate-imports"
        },

        schema: [
            {
                type: "object",
                properties: {
                    includeExports: {
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            import: "'{{module}}' import is duplicated.",
            importAs: "'{{module}}' import is duplicated as export.",
            export: "'{{module}}' export is duplicated.",
            exportAs: "'{{module}}' export is duplicated as import."
        }
    },

    create(context) {
        const includeExports = (context.options[0] || {}).includeExports,
            modules = new Map();
        const handlers = {
            ImportDeclaration: handleImportsExports(
                context,
                modules,
                "import",
                includeExports
            )
        };

        if (includeExports) {
            handlers.ExportNamedDeclaration = handleImportsExports(
                context,
                modules,
                "export",
                includeExports
            );
            handlers.ExportAllDeclaration = handleImportsExports(
                context,
                modules,
                "export",
                includeExports
            );
        }
        return handlers;
    }
};


code:
/**
 * @fileoverview Rule to flag `else` after a `return` in `if`
 * @author Ian Christian Myers
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");
const FixTracker = require("./utils/fix-tracker");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow `else` blocks after `return` statements in `if` statements",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-else-return"
        },

        schema: [{
            type: "object",
            properties: {
                allowElseIf: {
                    type: "boolean",
                    default: true
                }
            },
            additionalProperties: false
        }],

        fixable: "code",

        messages: {
            unexpected: "Unnecessary 'else' after 'return'."
        }
    },

    create(context) {

        const sourceCode = context.sourceCode;

        //--------------------------------------------------------------------------
        // Helpers
        //--------------------------------------------------------------------------

        /**
         * Checks whether the given names can be safely used to declare block-scoped variables
         * in the given scope. Name collisions can produce redeclaration syntax errors,
         * or silently change references and modify behavior of the original code.
         *
         * This is not a generic function. In particular, it is assumed that the scope is a function scope or
         * a function's inner scope, and that the names can be valid identifiers in the given scope.
         * @param {string[]} names Array of variable names.
         * @param {eslint-scope.Scope} scope Function scope or a function's inner scope.
         * @returns {boolean} True if all names can be safely declared, false otherwise.
         */
        function isSafeToDeclare(names, scope) {

            if (names.length === 0) {
                return true;
            }

            const functionScope = scope.variableScope;

            /*
             * If this is a function scope, scope.variables will contain parameters, implicit variables such as "arguments",
             * all function-scoped variables ('var'), and block-scoped variables defined in the scope.
             * If this is an inner scope, scope.variables will contain block-scoped variables defined in the scope.
             *
             * Redeclaring any of these would cause a syntax error, except for the implicit variables.
             */
            const declaredVariables = scope.variables.filter(({ defs }) => defs.length > 0);

            if (declaredVariables.some(({ name }) => names.includes(name))) {
                return false;
            }

            // Redeclaring a catch variable would also cause a syntax error.
            if (scope !== functionScope && scope.upper.type === "catch") {
                if (scope.upper.variables.some(({ name }) => names.includes(name))) {
                    return false;
                }
            }

            /*
             * Redeclaring an implicit variable, such as "arguments", would not cause a syntax error.
             * However, if the variable was used, declaring a new one with the same name would change references
             * and modify behavior.
             */
            const usedImplicitVariables = scope.variables.filter(({ defs, references }) =>
                defs.length === 0 && references.length > 0);

            if (usedImplicitVariables.some(({ name }) => names.includes(name))) {
                return false;
            }

            /*
             * Declaring a variable with a name that was already used to reference a variable from an upper scope
             * would change references and modify behavior.
             */
            if (scope.through.some(t => names.includes(t.identifier.name))) {
                return false;
            }

            /*
             * If the scope is an inner scope (not the function scope), an uninitialized `var` variable declared inside
             * the scope node (directly or in one of its descendants) is neither declared nor 'through' in the scope.
             *
             * For example, this would be a syntax error "Identifier 'a' has already been declared":
             * function foo() { if (bar) { let a; if (baz) { var a; } } }
             */
            if (scope !== functionScope) {
                const scopeNodeRange = scope.block.range;
                const variablesToCheck = functionScope.variables.filter(({ name }) => names.includes(name));

                if (variablesToCheck.some(v => v.defs.some(({ node: { range } }) =>
                    scopeNodeRange[0] <= range[0] && range[1] <= scopeNodeRange[1]))) {
                    return false;
                }
            }

            return true;
        }

        /**
         * Checks whether the removal of `else` and its braces is safe from variable name collisions.
         * @param {Node} node The 'else' node.
         * @param {eslint-scope.Scope} scope The scope in which the node and the whole 'if' statement is.
         * @returns {boolean} True if it is safe, false otherwise.
         */
        function isSafeFromNameCollisions(node, scope) {

            if (node.type === "FunctionDeclaration") {

                // Conditional function declaration. Scope and hoisting are unpredictable, different engines work differently.
                return false;
            }

            if (node.type !== "BlockStatement") {
                return true;
            }

            const elseBlockScope = scope.childScopes.find(({ block }) => block === node);

            if (!elseBlockScope) {

                // ecmaVersion < 6, `else` block statement cannot have its own scope, no possible collisions.
                return true;
            }

            /*
             * elseBlockScope is supposed to merge into its upper scope. elseBlockScope.variables array contains
             * only block-scoped variables (such as let and const variables or class and function declarations)
             * defined directly in the elseBlockScope. These are exactly the only names that could cause collisions.
             */
            const namesToCheck = elseBlockScope.variables.map(({ name }) => name);

            return isSafeToDeclare(namesToCheck, scope);
        }

        /**
         * Display the context report if rule is violated
         * @param {Node} elseNode The 'else' node
         * @returns {void}
         */
        function displayReport(elseNode) {
            const currentScope = sourceCode.getScope(elseNode.parent);

            context.report({
                node: elseNode,
                messageId: "unexpected",
                fix(fixer) {

                    if (!isSafeFromNameCollisions(elseNode, currentScope)) {
                        return null;
                    }

                    const startToken = sourceCode.getFirstToken(elseNode);
                    const elseToken = sourceCode.getTokenBefore(startToken);
                    const source = sourceCode.getText(elseNode);
                    const lastIfToken = sourceCode.getTokenBefore(elseToken);
                    let fixedSource, firstTokenOfElseBlock;

                    if (startToken.type === "Punctuator" && startToken.value === "{") {
                        firstTokenOfElseBlock = sourceCode.getTokenAfter(startToken);
                    } else {
                        firstTokenOfElseBlock = startToken;
                    }

                    /*
                     * If the if block does not have curly braces and does not end in a semicolon
                     * and the else block starts with (, [, /, +, ` or -, then it is not
                     * safe to remove the else keyword, because ASI will not add a semicolon
                     * after the if block
                     */
                    const ifBlockMaybeUnsafe = elseNode.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
                    const elseBlockUnsafe = /^[([/+`-]/u.test(firstTokenOfElseBlock.value);

                    if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
                        return null;
                    }

                    const endToken = sourceCode.getLastToken(elseNode);
                    const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);

                    if (lastTokenOfElseBlock.value !== ";") {
                        const nextToken = sourceCode.getTokenAfter(endToken);

                        const nextTokenUnsafe = nextToken && /^[([/+`-]/u.test(nextToken.value);
                        const nextTokenOnSameLine = nextToken && nextToken.loc.start.line === lastTokenOfElseBlock.loc.start.line;

                        /*
                         * If the else block contents does not end in a semicolon,
                         * and the else block starts with (, [, /, +, ` or -, then it is not
                         * safe to remove the else block, because ASI will not add a semicolon
                         * after the remaining else block contents
                         */
                        if (nextTokenUnsafe || (nextTokenOnSameLine && nextToken.value !== "}")) {
                            return null;
                        }
                    }

                    if (startToken.type === "Punctuator" && startToken.value === "{") {
                        fixedSource = source.slice(1, -1);
                    } else {
                        fixedSource = source;
                    }

                    /*
                     * Extend the replacement range to include the entire
                     * function to avoid conflicting with no-useless-return.
                     * https://github.com/eslint/eslint/issues/8026
                     *
                     * Also, to avoid name collisions between two else blocks.
                     */
                    return new FixTracker(fixer, sourceCode)
                        .retainEnclosingFunction(elseNode)
                        .replaceTextRange([elseToken.range[0], elseNode.range[1]], fixedSource);
                }
            });
        }

        /**
         * Check to see if the node is a ReturnStatement
         * @param {Node} node The node being evaluated
         * @returns {boolean} True if node is a return
         */
        function checkForReturn(node) {
            return node.type === "ReturnStatement";
        }

        /**
         * Naive return checking, does not iterate through the whole
         * BlockStatement because we make the assumption that the ReturnStatement
         * will be the last node in the body of the BlockStatement.
         * @param {Node} node The consequent/alternate node
         * @returns {boolean} True if it has a return
         */
        function naiveHasReturn(node) {
            if (node.type === "BlockStatement") {
                const body = node.body,
                    lastChildNode = body[body.length - 1];

                return lastChildNode && checkForReturn(lastChildNode);
            }
            return checkForReturn(node);
        }

        /**
         * Check to see if the node is valid for evaluation,
         * meaning it has an else.
         * @param {Node} node The node being evaluated
         * @returns {boolean} True if the node is valid
         */
        function hasElse(node) {
            return node.alternate && node.consequent;
        }

        /**
         * If the consequent is an IfStatement, check to see if it has an else
         * and both its consequent and alternate path return, meaning this is
         * a nested case of rule violation.  If-Else not considered currently.
         * @param {Node} node The consequent node
         * @returns {boolean} True if this is a nested rule violation
         */
        function checkForIf(node) {
            return node.type === "IfStatement" && hasElse(node) &&
                naiveHasReturn(node.alternate) && naiveHasReturn(node.consequent);
        }

        /**
         * Check the consequent/body node to make sure it is not
         * a ReturnStatement or an IfStatement that returns on both
         * code paths.
         * @param {Node} node The consequent or body node
         * @returns {boolean} `true` if it is a Return/If node that always returns.
         */
        function checkForReturnOrIf(node) {
            return checkForReturn(node) || checkForIf(node);
        }

        /**
         * Check whether a node returns in every codepath.
         * @param {Node} node The node to be checked
         * @returns {boolean} `true` if it returns on every codepath.
         */
        function alwaysReturns(node) {
            if (node.type === "BlockStatement") {

                // If we have a BlockStatement, check each consequent body node.
                return node.body.some(checkForReturnOrIf);
            }

            /*
             * If not a block statement, make sure the consequent isn't a
             * ReturnStatement or an IfStatement with returns on both paths.
             */
            return checkForReturnOrIf(node);
        }

        /**
         * Check the if statement, but don't catch else-if blocks.
         * @returns {void}
         * @param {Node} node The node for the if statement to check
         * @private
         */
        function checkIfWithoutElse(node) {
            const parent = node.parent;

            /*
             * Fixing this would require splitting one statement into two, so no error should
             * be reported if this node is in a position where only one statement is allowed.
             */
            if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
                return;
            }

            const consequents = [];
            let alternate;

            for (let currentNode = node; currentNode.type === "IfStatement"; currentNode = currentNode.alternate) {
                if (!currentNode.alternate) {
                    return;
                }
                consequents.push(currentNode.consequent);
                alternate = currentNode.alternate;
            }

            if (consequents.every(alwaysReturns)) {
                displayReport(alternate);
            }
        }

        /**
         * Check the if statement
         * @returns {void}
         * @param {Node} node The node for the if statement to check
         * @private
         */
        function checkIfWithElse(node) {
            const parent = node.parent;

            /*
             * Fixing this would require splitting one statement into two, so no error should
             * be reported if this node is in a position where only one statement is allowed.
             */
            if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
                return;
            }

            const alternate = node.alternate;

            if (alternate && alwaysReturns(node.consequent)) {
                displayReport(alternate);
            }
        }

        const allowElseIf = !(context.options[0] && context.options[0].allowElseIf === false);

        //--------------------------------------------------------------------------
        // Public API
        //--------------------------------------------------------------------------

        return {

            "IfStatement:exit": allowElseIf ? checkIfWithoutElse : checkIfWithElse

        };

    }
};


code:
/**
 * @fileoverview Rule to flag the use of empty character classes in regular expressions
 * @author Ian Christian Myers
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const parser = new RegExpParser();
const QUICK_TEST_REGEX = /\[\]/u;

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow empty character classes in regular expressions",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-empty-character-class"
        },

        schema: [],

        messages: {
            unexpected: "Empty class."
        }
    },

    create(context) {
        return {
            "Literal[regex]"(node) {
                const { pattern, flags } = node.regex;

                if (!QUICK_TEST_REGEX.test(pattern)) {
                    return;
                }

                let regExpAST;

                try {
                    regExpAST = parser.parsePattern(pattern, 0, pattern.length, {
                        unicode: flags.includes("u"),
                        unicodeSets: flags.includes("v")
                    });
                } catch {

                    // Ignore regular expressions that regexpp cannot parse
                    return;
                }

                visitRegExpAST(regExpAST, {
                    onCharacterClassEnter(characterClass) {
                        if (!characterClass.negate && characterClass.elements.length === 0) {
                            context.report({ node, messageId: "unexpected" });
                        }
                    }
                });
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to disallow empty functions.
 * @author Toru Nagashima
 */

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const ALLOW_OPTIONS = Object.freeze([
    "functions",
    "arrowFunctions",
    "generatorFunctions",
    "methods",
    "generatorMethods",
    "getters",
    "setters",
    "constructors",
    "asyncFunctions",
    "asyncMethods"
]);

/**
 * Gets the kind of a given function node.
 * @param {ASTNode} node A function node to get. This is one of
 *      an ArrowFunctionExpression, a FunctionDeclaration, or a
 *      FunctionExpression.
 * @returns {string} The kind of the function. This is one of "functions",
 *      "arrowFunctions", "generatorFunctions", "asyncFunctions", "methods",
 *      "generatorMethods", "asyncMethods", "getters", "setters", and
 *      "constructors".
 */
function getKind(node) {
    const parent = node.parent;
    let kind = "";

    if (node.type === "ArrowFunctionExpression") {
        return "arrowFunctions";
    }

    // Detects main kind.
    if (parent.type === "Property") {
        if (parent.kind === "get") {
            return "getters";
        }
        if (parent.kind === "set") {
            return "setters";
        }
        kind = parent.method ? "methods" : "functions";

    } else if (parent.type === "MethodDefinition") {
        if (parent.kind === "get") {
            return "getters";
        }
        if (parent.kind === "set") {
            return "setters";
        }
        if (parent.kind === "constructor") {
            return "constructors";
        }
        kind = "methods";

    } else {
        kind = "functions";
    }

    // Detects prefix.
    let prefix = "";

    if (node.generator) {
        prefix = "generator";
    } else if (node.async) {
        prefix = "async";
    } else {
        return kind;
    }
    return prefix + kind[0].toUpperCase() + kind.slice(1);
}

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow empty functions",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-empty-function"
        },

        schema: [
            {
                type: "object",
                properties: {
                    allow: {
                        type: "array",
                        items: { enum: ALLOW_OPTIONS },
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            unexpected: "Unexpected empty {{name}}."
        }
    },

    create(context) {
        const options = context.options[0] || {};
        const allowed = options.allow || [];

        const sourceCode = context.sourceCode;

        /**
         * Reports a given function node if the node matches the following patterns.
         *
         * - Not allowed by options.
         * - The body is empty.
         * - The body doesn't have any comments.
         * @param {ASTNode} node A function node to report. This is one of
         *      an ArrowFunctionExpression, a FunctionDeclaration, or a
         *      FunctionExpression.
         * @returns {void}
         */
        function reportIfEmpty(node) {
            const kind = getKind(node);
            const name = astUtils.getFunctionNameWithKind(node);
            const innerComments = sourceCode.getTokens(node.body, {
                includeComments: true,
                filter: astUtils.isCommentToken
            });

            if (!allowed.includes(kind) &&
                node.body.type === "BlockStatement" &&
                node.body.body.length === 0 &&
                innerComments.length === 0
            ) {
                context.report({
                    node,
                    loc: node.body.loc,
                    messageId: "unexpected",
                    data: { name }
                });
            }
        }

        return {
            ArrowFunctionExpression: reportIfEmpty,
            FunctionDeclaration: reportIfEmpty,
            FunctionExpression: reportIfEmpty
        };
    }
};


code:
/**
 * @fileoverview Rule to disallow an empty pattern
 * @author Alberto Rodríguez
 */
"use strict";

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow empty destructuring patterns",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/no-empty-pattern"
        },

        schema: [
            {
                type: "object",
                properties: {
                    allowObjectPatternsAsParameters: {
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            unexpected: "Unexpected empty {{type}} pattern."
        }
    },

    create(context) {
        const options = context.options[0] || {},
            allowObjectPatternsAsParameters = options.allowObjectPatternsAsParameters || false;

        return {
            ObjectPattern(node) {

                if (node.properties.length > 0) {
                    return;
                }

                // Allow {} and {} = {} empty object patterns as parameters when allowObjectPatternsAsParameters is true
                if (
                    allowObjectPatternsAsParameters &&
                    (
                        astUtils.isFunction(node.parent) ||
                        (
                            node.parent.type === "AssignmentPattern" &&
                            astUtils.isFunction(node.parent.parent) &&
                            node.parent.right.type === "ObjectExpression" &&
                            node.parent.right.properties.length === 0
                        )
                    )
                ) {
                    return;
                }

                context.report({ node, messageId: "unexpected", data: { type: "object" } });
            },
            ArrayPattern(node) {
                if (node.elements.length === 0) {
                    context.report({ node, messageId: "unexpected", data: { type: "array" } });
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to disallow empty static blocks.
 * @author Sosuke Suzuki
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description: "Disallow empty static blocks",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-empty-static-block"
        },

        schema: [],

        messages: {
            unexpected: "Unexpected empty static block."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;

        return {
            StaticBlock(node) {
                if (node.body.length === 0) {
                    const closingBrace = sourceCode.getLastToken(node);

                    if (sourceCode.getCommentsBefore(closingBrace).length === 0) {
                        context.report({
                            node,
                            messageId: "unexpected"
                        });
                    }
                }
            }
        };
    }
};