code:
/**
 * @fileoverview Disallow redundant return statements
 * @author Teddy Katz
 */
"use strict";

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

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

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

/**
 * Removes the given element from the array.
 * @param {Array} array The source array to remove.
 * @param {any} element The target item to remove.
 * @returns {void}
 */
function remove(array, element) {
    const index = array.indexOf(element);

    if (index !== -1) {
        array.splice(index, 1);
    }
}

/**
 * Checks whether it can remove the given return statement or not.
 * @param {ASTNode} node The return statement node to check.
 * @returns {boolean} `true` if the node is removable.
 */
function isRemovable(node) {
    return astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type);
}

/**
 * Checks whether the given return statement is in a `finally` block or not.
 * @param {ASTNode} node The return statement node to check.
 * @returns {boolean} `true` if the node is in a `finally` block.
 */
function isInFinally(node) {
    for (
        let currentNode = node;
        currentNode && currentNode.parent && !astUtils.isFunction(currentNode);
        currentNode = currentNode.parent
    ) {
        if (currentNode.parent.type === "TryStatement" && currentNode.parent.finalizer === currentNode) {
            return true;
        }
    }

    return false;
}

/**
 * Checks all segments in a set and returns true if any are reachable.
 * @param {Set<CodePathSegment>} segments The segments to check.
 * @returns {boolean} True if any segment is reachable; false otherwise.
 */
function isAnySegmentReachable(segments) {

    for (const segment of segments) {
        if (segment.reachable) {
            return true;
        }
    }

    return false;
}

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

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

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

        fixable: "code",
        schema: [],

        messages: {
            unnecessaryReturn: "Unnecessary return statement."
        }
    },

    create(context) {
        const segmentInfoMap = new WeakMap();
        const sourceCode = context.sourceCode;
        let scopeInfo = null;

        /**
         * Checks whether the given segment is terminated by a return statement or not.
         * @param {CodePathSegment} segment The segment to check.
         * @returns {boolean} `true` if the segment is terminated by a return statement, or if it's still a part of unreachable.
         */
        function isReturned(segment) {
            const info = segmentInfoMap.get(segment);

            return !info || info.returned;
        }

        /**
         * Collects useless return statements from the given previous segments.
         *
         * A previous segment may be an unreachable segment.
         * In that case, the information object of the unreachable segment is not
         * initialized because `onCodePathSegmentStart` event is not notified for
         * unreachable segments.
         * This goes to the previous segments of the unreachable segment recursively
         * if the unreachable segment was generated by a return statement. Otherwise,
         * this ignores the unreachable segment.
         *
         * This behavior would simulate code paths for the case that the return
         * statement does not exist.
         * @param {ASTNode[]} uselessReturns The collected return statements.
         * @param {CodePathSegment[]} prevSegments The previous segments to traverse.
         * @param {WeakSet<CodePathSegment>} [providedTraversedSegments] A set of segments that have already been traversed in this call
         * @returns {ASTNode[]} `uselessReturns`.
         */
        function getUselessReturns(uselessReturns, prevSegments, providedTraversedSegments) {
            const traversedSegments = providedTraversedSegments || new WeakSet();

            for (const segment of prevSegments) {
                if (!segment.reachable) {
                    if (!traversedSegments.has(segment)) {
                        traversedSegments.add(segment);
                        getUselessReturns(
                            uselessReturns,
                            segment.allPrevSegments.filter(isReturned),
                            traversedSegments
                        );
                    }
                    continue;
                }

                uselessReturns.push(...segmentInfoMap.get(segment).uselessReturns);
            }

            return uselessReturns;
        }

        /**
         * Removes the return statements on the given segment from the useless return
         * statement list.
         *
         * This segment may be an unreachable segment.
         * In that case, the information object of the unreachable segment is not
         * initialized because `onCodePathSegmentStart` event is not notified for
         * unreachable segments.
         * This goes to the previous segments of the unreachable segment recursively
         * if the unreachable segment was generated by a return statement. Otherwise,
         * this ignores the unreachable segment.
         *
         * This behavior would simulate code paths for the case that the return
         * statement does not exist.
         * @param {CodePathSegment} segment The segment to get return statements.
         * @param {Set<CodePathSegment>} usedUnreachableSegments A set of segments that have already been traversed in this call.
         * @returns {void}
         */
        function markReturnStatementsOnSegmentAsUsed(segment, usedUnreachableSegments) {
            if (!segment.reachable) {
                usedUnreachableSegments.add(segment);
                segment.allPrevSegments
                    .filter(isReturned)
                    .filter(prevSegment => !usedUnreachableSegments.has(prevSegment))
                    .forEach(prevSegment => markReturnStatementsOnSegmentAsUsed(prevSegment, usedUnreachableSegments));
                return;
            }

            const info = segmentInfoMap.get(segment);

            info.uselessReturns = info.uselessReturns.filter(node => {
                if (scopeInfo.traversedTryBlockStatements && scopeInfo.traversedTryBlockStatements.length > 0) {
                    const returnInitialRange = node.range[0];
                    const returnFinalRange = node.range[1];

                    const areBlocksInRange = scopeInfo.traversedTryBlockStatements.some(tryBlockStatement => {
                        const blockInitialRange = tryBlockStatement.range[0];
                        const blockFinalRange = tryBlockStatement.range[1];

                        return (
                            returnInitialRange >= blockInitialRange &&
                            returnFinalRange <= blockFinalRange
                        );
                    });

                    if (areBlocksInRange) {
                        return true;
                    }
                }

                remove(scopeInfo.uselessReturns, node);
                return false;
            });
        }

        /**
         * Removes the return statements on the current segments from the useless
         * return statement list.
         *
         * This function will be called at every statement except FunctionDeclaration,
         * BlockStatement, and BreakStatement.
         *
         * - FunctionDeclarations are always executed whether it's returned or not.
         * - BlockStatements do nothing.
         * - BreakStatements go the next merely.
         * @returns {void}
         */
        function markReturnStatementsOnCurrentSegmentsAsUsed() {
            scopeInfo
                .currentSegments
                .forEach(segment => markReturnStatementsOnSegmentAsUsed(segment, new Set()));
        }

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

        return {

            // Makes and pushes a new scope information.
            onCodePathStart(codePath) {
                scopeInfo = {
                    upper: scopeInfo,
                    uselessReturns: [],
                    traversedTryBlockStatements: [],
                    codePath,
                    currentSegments: new Set()
                };
            },

            // Reports useless return statements if exist.
            onCodePathEnd() {
                for (const node of scopeInfo.uselessReturns) {
                    context.report({
                        node,
                        loc: node.loc,
                        messageId: "unnecessaryReturn",
                        fix(fixer) {
                            if (isRemovable(node) && !sourceCode.getCommentsInside(node).length) {

                                /*
                                 * Extend the replacement range to include the
                                 * entire function to avoid conflicting with
                                 * no-else-return.
                                 * https://github.com/eslint/eslint/issues/8026
                                 */
                                return new FixTracker(fixer, sourceCode)
                                    .retainEnclosingFunction(node)
                                    .remove(node);
                            }
                            return null;
                        }
                    });
                }

                scopeInfo = scopeInfo.upper;
            },

            /*
             * Initializes segments.
             * NOTE: This event is notified for only reachable segments.
             */
            onCodePathSegmentStart(segment) {

                scopeInfo.currentSegments.add(segment);

                const info = {
                    uselessReturns: getUselessReturns([], segment.allPrevSegments),
                    returned: false
                };

                // Stores the info.
                segmentInfoMap.set(segment, info);
            },

            onUnreachableCodePathSegmentStart(segment) {
                scopeInfo.currentSegments.add(segment);
            },

            onUnreachableCodePathSegmentEnd(segment) {
                scopeInfo.currentSegments.delete(segment);
            },

            onCodePathSegmentEnd(segment) {
                scopeInfo.currentSegments.delete(segment);
            },

            // Adds ReturnStatement node to check whether it's useless or not.
            ReturnStatement(node) {
                if (node.argument) {
                    markReturnStatementsOnCurrentSegmentsAsUsed();
                }
                if (
                    node.argument ||
                    astUtils.isInLoop(node) ||
                    isInFinally(node) ||

                    // Ignore `return` statements in unreachable places (https://github.com/eslint/eslint/issues/11647).
                    !isAnySegmentReachable(scopeInfo.currentSegments)
                ) {
                    return;
                }

                for (const segment of scopeInfo.currentSegments) {
                    const info = segmentInfoMap.get(segment);

                    if (info) {
                        info.uselessReturns.push(node);
                        info.returned = true;
                    }
                }
                scopeInfo.uselessReturns.push(node);
            },

            "TryStatement > BlockStatement.block:exit"(node) {
                scopeInfo.traversedTryBlockStatements.push(node);
            },

            "TryStatement:exit"() {
                scopeInfo.traversedTryBlockStatements.pop();
            },

            /*
             * Registers for all statement nodes except FunctionDeclaration, BlockStatement, BreakStatement.
             * Removes return statements of the current segments from the useless return statement list.
             */
            ClassDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ContinueStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            DebuggerStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            DoWhileStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            EmptyStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExpressionStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForInStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForOfStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ForStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            IfStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ImportDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            LabeledStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            SwitchStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ThrowStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            TryStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            VariableDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            WhileStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            WithStatement: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportNamedDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportDefaultDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed,
            ExportAllDeclaration: markReturnStatementsOnCurrentSegmentsAsUsed
        };
    }
};


code:
/**
 * @fileoverview Rule to check for the usage of var.
 * @author Jamund Ferguson
 */

"use strict";

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

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

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

/**
 * Check whether a given variable is a global variable or not.
 * @param {eslint-scope.Variable} variable The variable to check.
 * @returns {boolean} `true` if the variable is a global variable.
 */
function isGlobal(variable) {
    return Boolean(variable.scope) && variable.scope.type === "global";
}

/**
 * Finds the nearest function scope or global scope walking up the scope
 * hierarchy.
 * @param {eslint-scope.Scope} scope The scope to traverse.
 * @returns {eslint-scope.Scope} a function scope or global scope containing the given
 *      scope.
 */
function getEnclosingFunctionScope(scope) {
    let currentScope = scope;

    while (currentScope.type !== "function" && currentScope.type !== "global") {
        currentScope = currentScope.upper;
    }
    return currentScope;
}

/**
 * Checks whether the given variable has any references from a more specific
 * function expression (i.e. a closure).
 * @param {eslint-scope.Variable} variable A variable to check.
 * @returns {boolean} `true` if the variable is used from a closure.
 */
function isReferencedInClosure(variable) {
    const enclosingFunctionScope = getEnclosingFunctionScope(variable.scope);

    return variable.references.some(reference =>
        getEnclosingFunctionScope(reference.from) !== enclosingFunctionScope);
}

/**
 * Checks whether the given node is the assignee of a loop.
 * @param {ASTNode} node A VariableDeclaration node to check.
 * @returns {boolean} `true` if the declaration is assigned as part of loop
 *      iteration.
 */
function isLoopAssignee(node) {
    return (node.parent.type === "ForOfStatement" || node.parent.type === "ForInStatement") &&
        node === node.parent.left;
}

/**
 * Checks whether the given variable declaration is immediately initialized.
 * @param {ASTNode} node A VariableDeclaration node to check.
 * @returns {boolean} `true` if the declaration has an initializer.
 */
function isDeclarationInitialized(node) {
    return node.declarations.every(declarator => declarator.init !== null);
}

const SCOPE_NODE_TYPE = /^(?:Program|BlockStatement|SwitchStatement|ForStatement|ForInStatement|ForOfStatement)$/u;

/**
 * Gets the scope node which directly contains a given node.
 * @param {ASTNode} node A node to get. This is a `VariableDeclaration` or
 *      an `Identifier`.
 * @returns {ASTNode} A scope node. This is one of `Program`, `BlockStatement`,
 *      `SwitchStatement`, `ForStatement`, `ForInStatement`, and
 *      `ForOfStatement`.
 */
function getScopeNode(node) {
    for (let currentNode = node; currentNode; currentNode = currentNode.parent) {
        if (SCOPE_NODE_TYPE.test(currentNode.type)) {
            return currentNode;
        }
    }

    /* c8 ignore next */
    return null;
}

/**
 * Checks whether a given variable is redeclared or not.
 * @param {eslint-scope.Variable} variable A variable to check.
 * @returns {boolean} `true` if the variable is redeclared.
 */
function isRedeclared(variable) {
    return variable.defs.length >= 2;
}

/**
 * Checks whether a given variable is used from outside of the specified scope.
 * @param {ASTNode} scopeNode A scope node to check.
 * @returns {Function} The predicate function which checks whether a given
 *      variable is used from outside of the specified scope.
 */
function isUsedFromOutsideOf(scopeNode) {

    /**
     * Checks whether a given reference is inside of the specified scope or not.
     * @param {eslint-scope.Reference} reference A reference to check.
     * @returns {boolean} `true` if the reference is inside of the specified
     *      scope.
     */
    function isOutsideOfScope(reference) {
        const scope = scopeNode.range;
        const id = reference.identifier.range;

        return id[0] < scope[0] || id[1] > scope[1];
    }

    return function(variable) {
        return variable.references.some(isOutsideOfScope);
    };
}

/**
 * Creates the predicate function which checks whether a variable has their references in TDZ.
 *
 * The predicate function would return `true`:
 *
 * - if a reference is before the declarator. E.g. (var a = b, b = 1;)(var {a = b, b} = {};)
 * - if a reference is in the expression of their default value.  E.g. (var {a = a} = {};)
 * - if a reference is in the expression of their initializer.  E.g. (var a = a;)
 * @param {ASTNode} node The initializer node of VariableDeclarator.
 * @returns {Function} The predicate function.
 * @private
 */
function hasReferenceInTDZ(node) {
    const initStart = node.range[0];
    const initEnd = node.range[1];

    return variable => {
        const id = variable.defs[0].name;
        const idStart = id.range[0];
        const defaultValue = (id.parent.type === "AssignmentPattern" ? id.parent.right : null);
        const defaultStart = defaultValue && defaultValue.range[0];
        const defaultEnd = defaultValue && defaultValue.range[1];

        return variable.references.some(reference => {
            const start = reference.identifier.range[0];
            const end = reference.identifier.range[1];

            return !reference.init && (
                start < idStart ||
                (defaultValue !== null && start >= defaultStart && end <= defaultEnd) ||
                (!astUtils.isFunction(node) && start >= initStart && end <= initEnd)
            );
        });
    };
}

/**
 * Checks whether a given variable has name that is allowed for 'var' declarations,
 * but disallowed for `let` declarations.
 * @param {eslint-scope.Variable} variable The variable to check.
 * @returns {boolean} `true` if the variable has a disallowed name.
 */
function hasNameDisallowedForLetDeclarations(variable) {
    return variable.name === "let";
}

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

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

        docs: {
            description: "Require `let` or `const` instead of `var`",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-var"
        },

        schema: [],
        fixable: "code",

        messages: {
            unexpectedVar: "Unexpected var, use let or const instead."
        }
    },

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

        /**
         * Checks whether the variables which are defined by the given declarator node have their references in TDZ.
         * @param {ASTNode} declarator The VariableDeclarator node to check.
         * @returns {boolean} `true` if one of the variables which are defined by the given declarator node have their references in TDZ.
         */
        function hasSelfReferenceInTDZ(declarator) {
            if (!declarator.init) {
                return false;
            }
            const variables = sourceCode.getDeclaredVariables(declarator);

            return variables.some(hasReferenceInTDZ(declarator.init));
        }

        /**
         * Checks whether it can fix a given variable declaration or not.
         * It cannot fix if the following cases:
         *
         * - A variable is a global variable.
         * - A variable is declared on a SwitchCase node.
         * - A variable is redeclared.
         * - A variable is used from outside the scope.
         * - A variable is used from a closure within a loop.
         * - A variable might be used before it is assigned within a loop.
         * - A variable might be used in TDZ.
         * - A variable is declared in statement position (e.g. a single-line `IfStatement`)
         * - A variable has name that is disallowed for `let` declarations.
         *
         * ## A variable is declared on a SwitchCase node.
         *
         * If this rule modifies 'var' declarations on a SwitchCase node, it
         * would generate the warnings of 'no-case-declarations' rule. And the
         * 'eslint:recommended' preset includes 'no-case-declarations' rule, so
         * this rule doesn't modify those declarations.
         *
         * ## A variable is redeclared.
         *
         * The language spec disallows redeclarations of `let` declarations.
         * Those variables would cause syntax errors.
         *
         * ## A variable is used from outside the scope.
         *
         * The language spec disallows accesses from outside of the scope for
         * `let` declarations. Those variables would cause reference errors.
         *
         * ## A variable is used from a closure within a loop.
         *
         * A `var` declaration within a loop shares the same variable instance
         * across all loop iterations, while a `let` declaration creates a new
         * instance for each iteration. This means if a variable in a loop is
         * referenced by any closure, changing it from `var` to `let` would
         * change the behavior in a way that is generally unsafe.
         *
         * ## A variable might be used before it is assigned within a loop.
         *
         * Within a loop, a `let` declaration without an initializer will be
         * initialized to null, while a `var` declaration will retain its value
         * from the previous iteration, so it is only safe to change `var` to
         * `let` if we can statically determine that the variable is always
         * assigned a value before its first access in the loop body. To keep
         * the implementation simple, we only convert `var` to `let` within
         * loops when the variable is a loop assignee or the declaration has an
         * initializer.
         * @param {ASTNode} node A variable declaration node to check.
         * @returns {boolean} `true` if it can fix the node.
         */
        function canFix(node) {
            const variables = sourceCode.getDeclaredVariables(node);
            const scopeNode = getScopeNode(node);

            if (node.parent.type === "SwitchCase" ||
                node.declarations.some(hasSelfReferenceInTDZ) ||
                variables.some(isGlobal) ||
                variables.some(isRedeclared) ||
                variables.some(isUsedFromOutsideOf(scopeNode)) ||
                variables.some(hasNameDisallowedForLetDeclarations)
            ) {
                return false;
            }

            if (astUtils.isInLoop(node)) {
                if (variables.some(isReferencedInClosure)) {
                    return false;
                }
                if (!isLoopAssignee(node) && !isDeclarationInitialized(node)) {
                    return false;
                }
            }

            if (
                !isLoopAssignee(node) &&
                !(node.parent.type === "ForStatement" && node.parent.init === node) &&
                !astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)
            ) {

                // If the declaration is not in a block, e.g. `if (foo) var bar = 1;`, then it can't be fixed.
                return false;
            }

            return true;
        }

        /**
         * Reports a given variable declaration node.
         * @param {ASTNode} node A variable declaration node to report.
         * @returns {void}
         */
        function report(node) {
            context.report({
                node,
                messageId: "unexpectedVar",

                fix(fixer) {
                    const varToken = sourceCode.getFirstToken(node, { filter: t => t.value === "var" });

                    return canFix(node)
                        ? fixer.replaceText(varToken, "let")
                        : null;
                }
            });
        }

        return {
            "VariableDeclaration:exit"(node) {
                if (node.kind === "var") {
                    report(node);
                }
            }
        };
    }
};

license: mit


code:
/**
 * @fileoverview Rule to disallow use of void operator.
 * @author Mike Sidorov
 */
"use strict";

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

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

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

        messages: {
            noVoid: "Expected 'undefined' and instead saw 'void'."
        },

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

    create(context) {
        const allowAsStatement =
            context.options[0] && context.options[0].allowAsStatement;

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

        return {
            'UnaryExpression[operator="void"]'(node) {
                if (
                    allowAsStatement &&
                    node.parent &&
                    node.parent.type === "ExpressionStatement"
                ) {
                    return;
                }
                context.report({
                    node,
                    messageId: "noVoid"
                });
            }
        };
    }
};


code:
/**
 * @fileoverview Rule that warns about used warning comments
 * @author Alexander Schmidt <https://github.com/lxanders>
 */

"use strict";

const escapeRegExp = require("escape-string-regexp");
const astUtils = require("./utils/ast-utils");

const CHAR_LIMIT = 40;

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

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

        docs: {
            description: "Disallow specified warning terms in comments",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-warning-comments"
        },

        schema: [
            {
                type: "object",
                properties: {
                    terms: {
                        type: "array",
                        items: {
                            type: "string"
                        }
                    },
                    location: {
                        enum: ["start", "anywhere"]
                    },
                    decoration: {
                        type: "array",
                        items: {
                            type: "string",
                            pattern: "^\\S$"
                        },
                        minItems: 1,
                        uniqueItems: true
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            unexpectedComment: "Unexpected '{{matchedTerm}}' comment: '{{comment}}'."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode,
            configuration = context.options[0] || {},
            warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
            location = configuration.location || "start",
            decoration = [...configuration.decoration || []].join(""),
            selfConfigRegEx = /\bno-warning-comments\b/u;

        /**
         * Convert a warning term into a RegExp which will match a comment containing that whole word in the specified
         * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not
         * require word boundaries on that side.
         * @param {string} term A term to convert to a RegExp
         * @returns {RegExp} The term converted to a RegExp
         */
        function convertToRegExp(term) {
            const escaped = escapeRegExp(term);
            const escapedDecoration = escapeRegExp(decoration);

            /*
             * When matching at the start, ignore leading whitespace, and
             * there's no need to worry about word boundaries.
             *
             * These expressions for the prefix and suffix are designed as follows:
             * ^   handles any terms at the beginning of a comment.
             *     e.g. terms ["TODO"] matches `//TODO something`
             * $   handles any terms at the end of a comment
             *     e.g. terms ["TODO"] matches `// something TODO`
             * \b  handles terms preceded/followed by word boundary
             *     e.g. terms: ["!FIX", "FIX!"] matches `// FIX!something` or `// something!FIX`
             *          terms: ["FIX"] matches `// FIX!` or `// !FIX`, but not `// fixed or affix`
             *
             * For location start:
             * [\s]* handles optional leading spaces
             *     e.g. terms ["TODO"] matches `//    TODO something`
             * [\s\*]* (where "\*" is the escaped string of decoration)
             *     handles optional leading spaces or decoration characters (for "start" location only)
             *     e.g. terms ["TODO"] matches `/**** TODO something ... `
             */
            const wordBoundary = "\\b";

            let prefix = "";

            if (location === "start") {
                prefix = `^[\\s${escapedDecoration}]*`;
            } else if (/^\w/u.test(term)) {
                prefix = wordBoundary;
            }

            const suffix = /\w$/u.test(term) ? wordBoundary : "";
            const flags = "iu"; // Case-insensitive with Unicode case folding.

            /*
             * For location "start", the typical regex is:
             *   /^[\s]*ESCAPED_TERM\b/iu.
             * Or if decoration characters are specified (e.g. "*"), then any of
             * those characters may appear in any order at the start:
             *   /^[\s\*]*ESCAPED_TERM\b/iu.
             *
             * For location "anywhere" the typical regex is
             *   /\bESCAPED_TERM\b/iu
             *
             * If it starts or ends with non-word character, the prefix and suffix are empty, respectively.
             */
            return new RegExp(`${prefix}${escaped}${suffix}`, flags);
        }

        const warningRegExps = warningTerms.map(convertToRegExp);

        /**
         * Checks the specified comment for matches of the configured warning terms and returns the matches.
         * @param {string} comment The comment which is checked.
         * @returns {Array} All matched warning terms for this comment.
         */
        function commentContainsWarningTerm(comment) {
            const matches = [];

            warningRegExps.forEach((regex, index) => {
                if (regex.test(comment)) {
                    matches.push(warningTerms[index]);
                }
            });

            return matches;
        }

        /**
         * Checks the specified node for matching warning comments and reports them.
         * @param {ASTNode} node The AST node being checked.
         * @returns {void} undefined.
         */
        function checkComment(node) {
            const comment = node.value;

            if (
                astUtils.isDirectiveComment(node) &&
                selfConfigRegEx.test(comment)
            ) {
                return;
            }

            const matches = commentContainsWarningTerm(comment);

            matches.forEach(matchedTerm => {
                let commentToDisplay = "";
                let truncated = false;

                for (const c of comment.trim().split(/\s+/u)) {
                    const tmp = commentToDisplay ? `${commentToDisplay} ${c}` : c;

                    if (tmp.length <= CHAR_LIMIT) {
                        commentToDisplay = tmp;
                    } else {
                        truncated = true;
                        break;
                    }
                }

                context.report({
                    node,
                    messageId: "unexpectedComment",
                    data: {
                        matchedTerm,
                        comment: `${commentToDisplay}${
                            truncated ? "..." : ""
                        }`
                    }
                });
            });
        }

        return {
            Program() {
                const comments = sourceCode.getAllComments();

                comments
                    .filter(token => token.type !== "Shebang")
                    .forEach(checkComment);
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to disallow whitespace before properties
 * @author Kai Cataldo
 * @deprecated in ESLint v8.53.0
 */
"use strict";

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

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

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

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        deprecated: true,
        replacedBy: [],
        type: "layout",

        docs: {
            description: "Disallow whitespace before properties",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/no-whitespace-before-property"
        },

        fixable: "whitespace",
        schema: [],

        messages: {
            unexpectedWhitespace: "Unexpected whitespace before property {{propName}}."
        }
    },

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

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

        /**
         * Reports whitespace before property token
         * @param {ASTNode} node the node to report in the event of an error
         * @param {Token} leftToken the left token
         * @param {Token} rightToken the right token
         * @returns {void}
         * @private
         */
        function reportError(node, leftToken, rightToken) {
            context.report({
                node,
                messageId: "unexpectedWhitespace",
                data: {
                    propName: sourceCode.getText(node.property)
                },
                fix(fixer) {
                    let replacementText = "";

                    if (!node.computed && !node.optional && astUtils.isDecimalInteger(node.object)) {

                        /*
                         * If the object is a number literal, fixing it to something like 5.toString() would cause a SyntaxError.
                         * Don't fix this case.
                         */
                        return null;
                    }

                    // Don't fix if comments exist.
                    if (sourceCode.commentsExistBetween(leftToken, rightToken)) {
                        return null;
                    }

                    if (node.optional) {
                        replacementText = "?.";
                    } else if (!node.computed) {
                        replacementText = ".";
                    }

                    return fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], replacementText);
                }
            });
        }

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

        return {
            MemberExpression(node) {
                let rightToken;
                let leftToken;

                if (!astUtils.isTokenOnSameLine(node.object, node.property)) {
                    return;
                }

                if (node.computed) {
                    rightToken = sourceCode.getTokenBefore(node.property, astUtils.isOpeningBracketToken);
                    leftToken = sourceCode.getTokenBefore(rightToken, node.optional ? 1 : 0);
                } else {
                    rightToken = sourceCode.getFirstToken(node.property);
                    leftToken = sourceCode.getTokenBefore(rightToken, 1);
                }

                if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) {
                    reportError(node, leftToken, rightToken);
                }
            }
        };
    }
};


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

"use strict";

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

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

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

        schema: [],

        messages: {
            unexpectedWith: "Unexpected use of 'with' statement."
        }
    },

    create(context) {

        return {
            WithStatement(node) {
                context.report({ node, messageId: "unexpectedWith" });
            }
        };

    }
};


code:
/**
 * @fileoverview enforce the location of single-line statements
 * @author Teddy Katz
 * @deprecated in ESLint v8.53.0
 */
"use strict";

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

const POSITION_SCHEMA = { enum: ["beside", "below", "any"] };

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        deprecated: true,
        replacedBy: [],
        type: "layout",

        docs: {
            description: "Enforce the location of single-line statements",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/nonblock-statement-body-position"
        },

        fixable: "whitespace",

        schema: [
            POSITION_SCHEMA,
            {
                properties: {
                    overrides: {
                        properties: {
                            if: POSITION_SCHEMA,
                            else: POSITION_SCHEMA,
                            while: POSITION_SCHEMA,
                            do: POSITION_SCHEMA,
                            for: POSITION_SCHEMA
                        },
                        additionalProperties: false
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            expectNoLinebreak: "Expected no linebreak before this statement.",
            expectLinebreak: "Expected a linebreak before this statement."
        }
    },

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

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

        /**
         * Gets the applicable preference for a particular keyword
         * @param {string} keywordName The name of a keyword, e.g. 'if'
         * @returns {string} The applicable option for the keyword, e.g. 'beside'
         */
        function getOption(keywordName) {
            return context.options[1] && context.options[1].overrides && context.options[1].overrides[keywordName] ||
                context.options[0] ||
                "beside";
        }

        /**
         * Validates the location of a single-line statement
         * @param {ASTNode} node The single-line statement
         * @param {string} keywordName The applicable keyword name for the single-line statement
         * @returns {void}
         */
        function validateStatement(node, keywordName) {
            const option = getOption(keywordName);

            if (node.type === "BlockStatement" || option === "any") {
                return;
            }

            const tokenBefore = sourceCode.getTokenBefore(node);

            if (tokenBefore.loc.end.line === node.loc.start.line && option === "below") {
                context.report({
                    node,
                    messageId: "expectLinebreak",
                    fix: fixer => fixer.insertTextBefore(node, "\n")
                });
            } else if (tokenBefore.loc.end.line !== node.loc.start.line && option === "beside") {
                context.report({
                    node,
                    messageId: "expectNoLinebreak",
                    fix(fixer) {
                        if (sourceCode.getText().slice(tokenBefore.range[1], node.range[0]).trim()) {
                            return null;
                        }
                        return fixer.replaceTextRange([tokenBefore.range[1], node.range[0]], " ");
                    }
                });
            }
        }

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

        return {
            IfStatement(node) {
                validateStatement(node.consequent, "if");

                // Check the `else` node, but don't check 'else if' statements.
                if (node.alternate && node.alternate.type !== "IfStatement") {
                    validateStatement(node.alternate, "else");
                }
            },
            WhileStatement: node => validateStatement(node.body, "while"),
            DoWhileStatement: node => validateStatement(node.body, "do"),
            ForStatement: node => validateStatement(node.body, "for"),
            ForInStatement: node => validateStatement(node.body, "for"),
            ForOfStatement: node => validateStatement(node.body, "for")
        };
    }
};


code:
/**
 * @fileoverview Rule to require or disallow line breaks inside braces.
 * @author Toru Nagashima
 * @deprecated in ESLint v8.53.0
 */

"use strict";

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

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

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

// Schema objects.
const OPTION_VALUE = {
    oneOf: [
        {
            enum: ["always", "never"]
        },
        {
            type: "object",
            properties: {
                multiline: {
                    type: "boolean"
                },
                minProperties: {
                    type: "integer",
                    minimum: 0
                },
                consistent: {
                    type: "boolean"
                }
            },
            additionalProperties: false,
            minProperties: 1
        }
    ]
};

/**
 * Normalizes a given option value.
 * @param {string|Object|undefined} value An option value to parse.
 * @returns {{multiline: boolean, minProperties: number, consistent: boolean}} Normalized option object.
 */
function normalizeOptionValue(value) {
    let multiline = false;
    let minProperties = Number.POSITIVE_INFINITY;
    let consistent = false;

    if (value) {
        if (value === "always") {
            minProperties = 0;
        } else if (value === "never") {
            minProperties = Number.POSITIVE_INFINITY;
        } else {
            multiline = Boolean(value.multiline);
            minProperties = value.minProperties || Number.POSITIVE_INFINITY;
            consistent = Boolean(value.consistent);
        }
    } else {
        consistent = true;
    }

    return { multiline, minProperties, consistent };
}

/**
 * Checks if a value is an object.
 * @param {any} value The value to check
 * @returns {boolean} `true` if the value is an object, otherwise `false`
 */
function isObject(value) {
    return typeof value === "object" && value !== null;
}

/**
 * Checks if an option is a node-specific option
 * @param {any} option The option to check
 * @returns {boolean} `true` if the option is node-specific, otherwise `false`
 */
function isNodeSpecificOption(option) {
    return isObject(option) || typeof option === "string";
}

/**
 * Normalizes a given option value.
 * @param {string|Object|undefined} options An option value to parse.
 * @returns {{
 *   ObjectExpression: {multiline: boolean, minProperties: number, consistent: boolean},
 *   ObjectPattern: {multiline: boolean, minProperties: number, consistent: boolean},
 *   ImportDeclaration: {multiline: boolean, minProperties: number, consistent: boolean},
 *   ExportNamedDeclaration : {multiline: boolean, minProperties: number, consistent: boolean}
 * }} Normalized option object.
 */
function normalizeOptions(options) {
    if (isObject(options) && Object.values(options).some(isNodeSpecificOption)) {
        return {
            ObjectExpression: normalizeOptionValue(options.ObjectExpression),
            ObjectPattern: normalizeOptionValue(options.ObjectPattern),
            ImportDeclaration: normalizeOptionValue(options.ImportDeclaration),
            ExportNamedDeclaration: normalizeOptionValue(options.ExportDeclaration)
        };
    }

    const value = normalizeOptionValue(options);

    return { ObjectExpression: value, ObjectPattern: value, ImportDeclaration: value, ExportNamedDeclaration: value };
}

/**
 * Determines if ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration
 * node needs to be checked for missing line breaks
 * @param {ASTNode} node Node under inspection
 * @param {Object} options option specific to node type
 * @param {Token} first First object property
 * @param {Token} last Last object property
 * @returns {boolean} `true` if node needs to be checked for missing line breaks
 */
function areLineBreaksRequired(node, options, first, last) {
    let objectProperties;

    if (node.type === "ObjectExpression" || node.type === "ObjectPattern") {
        objectProperties = node.properties;
    } else {

        // is ImportDeclaration or ExportNamedDeclaration
        objectProperties = node.specifiers
            .filter(s => s.type === "ImportSpecifier" || s.type === "ExportSpecifier");
    }

    return objectProperties.length >= options.minProperties ||
        (
            options.multiline &&
            objectProperties.length > 0 &&
            first.loc.start.line !== last.loc.end.line
        );
}

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

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        deprecated: true,
        replacedBy: [],
        type: "layout",

        docs: {
            description: "Enforce consistent line breaks after opening and before closing braces",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/object-curly-newline"
        },

        fixable: "whitespace",

        schema: [
            {
                oneOf: [
                    OPTION_VALUE,
                    {
                        type: "object",
                        properties: {
                            ObjectExpression: OPTION_VALUE,
                            ObjectPattern: OPTION_VALUE,
                            ImportDeclaration: OPTION_VALUE,
                            ExportDeclaration: OPTION_VALUE
                        },
                        additionalProperties: false,
                        minProperties: 1
                    }
                ]
            }
        ],

        messages: {
            unexpectedLinebreakBeforeClosingBrace: "Unexpected line break before this closing brace.",
            unexpectedLinebreakAfterOpeningBrace: "Unexpected line break after this opening brace.",
            expectedLinebreakBeforeClosingBrace: "Expected a line break before this closing brace.",
            expectedLinebreakAfterOpeningBrace: "Expected a line break after this opening brace."
        }
    },

    create(context) {
        const sourceCode = context.sourceCode;
        const normalizedOptions = normalizeOptions(context.options[0]);

        /**
         * Reports a given node if it violated this rule.
         * @param {ASTNode} node A node to check. This is an ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration node.
         * @returns {void}
         */
        function check(node) {
            const options = normalizedOptions[node.type];

            if (
                (node.type === "ImportDeclaration" &&
                    !node.specifiers.some(specifier => specifier.type === "ImportSpecifier")) ||
                (node.type === "ExportNamedDeclaration" &&
                    !node.specifiers.some(specifier => specifier.type === "ExportSpecifier"))
            ) {
                return;
            }

            const openBrace = sourceCode.getFirstToken(node, token => token.value === "{");

            let closeBrace;

            if (node.typeAnnotation) {
                closeBrace = sourceCode.getTokenBefore(node.typeAnnotation);
            } else {
                closeBrace = sourceCode.getLastToken(node, token => token.value === "}");
            }

            let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
            let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });

            const needsLineBreaks = areLineBreaksRequired(node, options, first, last);

            const hasCommentsFirstToken = astUtils.isCommentToken(first);
            const hasCommentsLastToken = astUtils.isCommentToken(last);

            /*
             * Use tokens or comments to check multiline or not.
             * But use only tokens to check whether line breaks are needed.
             * This allows:
             *     var obj = { // eslint-disable-line foo
             *         a: 1
             *     }
             */
            first = sourceCode.getTokenAfter(openBrace);
            last = sourceCode.getTokenBefore(closeBrace);

            if (needsLineBreaks) {
                if (astUtils.isTokenOnSameLine(openBrace, first)) {
                    context.report({
                        messageId: "expectedLinebreakAfterOpeningBrace",
                        node,
                        loc: openBrace.loc,
                        fix(fixer) {
                            if (hasCommentsFirstToken) {
                                return null;
                            }

                            return fixer.insertTextAfter(openBrace, "\n");
                        }
                    });
                }
                if (astUtils.isTokenOnSameLine(last, closeBrace)) {
                    context.report({
                        messageId: "expectedLinebreakBeforeClosingBrace",
                        node,
                        loc: closeBrace.loc,
                        fix(fixer) {
                            if (hasCommentsLastToken) {
                                return null;
                            }

                            return fixer.insertTextBefore(closeBrace, "\n");
                        }
                    });
                }
            } else {
                const consistent = options.consistent;
                const hasLineBreakBetweenOpenBraceAndFirst = !astUtils.isTokenOnSameLine(openBrace, first);
                const hasLineBreakBetweenCloseBraceAndLast = !astUtils.isTokenOnSameLine(last, closeBrace);

                if (
                    (!consistent && hasLineBreakBetweenOpenBraceAndFirst) ||
                    (consistent && hasLineBreakBetweenOpenBraceAndFirst && !hasLineBreakBetweenCloseBraceAndLast)
                ) {
                    context.report({
                        messageId: "unexpectedLinebreakAfterOpeningBrace",
                        node,
                        loc: openBrace.loc,
                        fix(fixer) {
                            if (hasCommentsFirstToken) {
                                return null;
                            }

                            return fixer.removeRange([
                                openBrace.range[1],
                                first.range[0]
                            ]);
                        }
                    });
                }
                if (
                    (!consistent && hasLineBreakBetweenCloseBraceAndLast) ||
                    (consistent && !hasLineBreakBetweenOpenBraceAndFirst && hasLineBreakBetweenCloseBraceAndLast)
                ) {
                    context.report({
                        messageId: "unexpectedLinebreakBeforeClosingBrace",
                        node,
                        loc: closeBrace.loc,
                        fix(fixer) {
                            if (hasCommentsLastToken) {
                                return null;
                            }

                            return fixer.removeRange([
                                last.range[1],
                                closeBrace.range[0]
                            ]);
                        }
                    });
                }
            }
        }

        return {
            ObjectExpression: check,
            ObjectPattern: check,
            ImportDeclaration: check,
            ExportNamedDeclaration: check
        };
    }
};


code:
/**
 * @fileoverview Disallows or enforces spaces inside of object literals.
 * @author Jamund Ferguson
 * @deprecated in ESLint v8.53.0
 */
"use strict";

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

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

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        deprecated: true,
        replacedBy: [],
        type: "layout",

        docs: {
            description: "Enforce consistent spacing inside braces",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/object-curly-spacing"
        },

        fixable: "whitespace",

        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    arraysInObjects: {
                        type: "boolean"
                    },
                    objectsInObjects: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            requireSpaceBefore: "A space is required before '{{token}}'.",
            requireSpaceAfter: "A space is required after '{{token}}'.",
            unexpectedSpaceBefore: "There should be no space before '{{token}}'.",
            unexpectedSpaceAfter: "There should be no space after '{{token}}'."
        }
    },

    create(context) {
        const spaced = context.options[0] === "always",
            sourceCode = context.sourceCode;

        /**
         * Determines whether an option is set, relative to the spacing option.
         * If spaced is "always", then check whether option is set to false.
         * If spaced is "never", then check whether option is set to true.
         * @param {Object} option The option to exclude.
         * @returns {boolean} Whether or not the property is excluded.
         */
        function isOptionSet(option) {
            return context.options[1] ? context.options[1][option] === !spaced : false;
        }

        const options = {
            spaced,
            arraysInObjectsException: isOptionSet("arraysInObjects"),
            objectsInObjectsException: isOptionSet("objectsInObjects")
        };

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

        /**
         * Reports that there shouldn't be a space after the first token
         * @param {ASTNode} node The node to report in the event of an error.
         * @param {Token} token The token to use for the report.
         * @returns {void}
         */
        function reportNoBeginningSpace(node, token) {
            const nextToken = context.sourceCode.getTokenAfter(token, { includeComments: true });

            context.report({
                node,
                loc: { start: token.loc.end, end: nextToken.loc.start },
                messageId: "unexpectedSpaceAfter",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.removeRange([token.range[1], nextToken.range[0]]);
                }
            });
        }

        /**
         * Reports that there shouldn't be a space before the last token
         * @param {ASTNode} node The node to report in the event of an error.
         * @param {Token} token The token to use for the report.
         * @returns {void}
         */
        function reportNoEndingSpace(node, token) {
            const previousToken = context.sourceCode.getTokenBefore(token, { includeComments: true });

            context.report({
                node,
                loc: { start: previousToken.loc.end, end: token.loc.start },
                messageId: "unexpectedSpaceBefore",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.removeRange([previousToken.range[1], token.range[0]]);
                }
            });
        }

        /**
         * Reports that there should be a space after the first token
         * @param {ASTNode} node The node to report in the event of an error.
         * @param {Token} token The token to use for the report.
         * @returns {void}
         */
        function reportRequiredBeginningSpace(node, token) {
            context.report({
                node,
                loc: token.loc,
                messageId: "requireSpaceAfter",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.insertTextAfter(token, " ");
                }
            });
        }

        /**
         * Reports that there should be a space before the last token
         * @param {ASTNode} node The node to report in the event of an error.
         * @param {Token} token The token to use for the report.
         * @returns {void}
         */
        function reportRequiredEndingSpace(node, token) {
            context.report({
                node,
                loc: token.loc,
                messageId: "requireSpaceBefore",
                data: {
                    token: token.value
                },
                fix(fixer) {
                    return fixer.insertTextBefore(token, " ");
                }
            });
        }

        /**
         * Determines if spacing in curly braces is valid.
         * @param {ASTNode} node The AST node to check.
         * @param {Token} first The first token to check (should be the opening brace)
         * @param {Token} second The second token to check (should be first after the opening brace)
         * @param {Token} penultimate The penultimate token to check (should be last before closing brace)
         * @param {Token} last The last token to check (should be closing brace)
         * @returns {void}
         */
        function validateBraceSpacing(node, first, second, penultimate, last) {
            if (astUtils.isTokenOnSameLine(first, second)) {
                const firstSpaced = sourceCode.isSpaceBetweenTokens(first, second);

                if (options.spaced && !firstSpaced) {
                    reportRequiredBeginningSpace(node, first);
                }
                if (!options.spaced && firstSpaced && second.type !== "Line") {
                    reportNoBeginningSpace(node, first);
                }
            }

            if (astUtils.isTokenOnSameLine(penultimate, last)) {
                const shouldCheckPenultimate = (
                    options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) ||
                    options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate)
                );
                const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.range[0]).type;

                const closingCurlyBraceMustBeSpaced = (
                    options.arraysInObjectsException && penultimateType === "ArrayExpression" ||
                    options.objectsInObjectsException && (penultimateType === "ObjectExpression" || penultimateType === "ObjectPattern")
                ) ? !options.spaced : options.spaced;

                const lastSpaced = sourceCode.isSpaceBetweenTokens(penultimate, last);

                if (closingCurlyBraceMustBeSpaced && !lastSpaced) {
                    reportRequiredEndingSpace(node, last);
                }
                if (!closingCurlyBraceMustBeSpaced && lastSpaced) {
                    reportNoEndingSpace(node, last);
                }
            }
        }

        /**
         * Gets '}' token of an object node.
         *
         * Because the last token of object patterns might be a type annotation,
         * this traverses tokens preceded by the last property, then returns the
         * first '}' token.
         * @param {ASTNode} node The node to get. This node is an
         *      ObjectExpression or an ObjectPattern. And this node has one or
         *      more properties.
         * @returns {Token} '}' token.
         */
        function getClosingBraceOfObject(node) {
            const lastProperty = node.properties[node.properties.length - 1];

            return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
        }

        /**
         * Reports a given object node if spacing in curly braces is invalid.
         * @param {ASTNode} node An ObjectExpression or ObjectPattern node to check.
         * @returns {void}
         */
        function checkForObject(node) {
            if (node.properties.length === 0) {
                return;
            }

            const first = sourceCode.getFirstToken(node),
                last = getClosingBraceOfObject(node),
                second = sourceCode.getTokenAfter(first, { includeComments: true }),
                penultimate = sourceCode.getTokenBefore(last, { includeComments: true });

            validateBraceSpacing(node, first, second, penultimate, last);
        }

        /**
         * Reports a given import node if spacing in curly braces is invalid.
         * @param {ASTNode} node An ImportDeclaration node to check.
         * @returns {void}
         */
        function checkForImport(node) {
            if (node.specifiers.length === 0) {
                return;
            }

            let firstSpecifier = node.specifiers[0];
            const lastSpecifier = node.specifiers[node.specifiers.length - 1];

            if (lastSpecifier.type !== "ImportSpecifier") {
                return;
            }
            if (firstSpecifier.type !== "ImportSpecifier") {
                firstSpecifier = node.specifiers[1];
            }

            const first = sourceCode.getTokenBefore(firstSpecifier),
                last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
                second = sourceCode.getTokenAfter(first, { includeComments: true }),
                penultimate = sourceCode.getTokenBefore(last, { includeComments: true });

            validateBraceSpacing(node, first, second, penultimate, last);
        }

        /**
         * Reports a given export node if spacing in curly braces is invalid.
         * @param {ASTNode} node An ExportNamedDeclaration node to check.
         * @returns {void}
         */
        function checkForExport(node) {
            if (node.specifiers.length === 0) {
                return;
            }

            const firstSpecifier = node.specifiers[0],
                lastSpecifier = node.specifiers[node.specifiers.length - 1],
                first = sourceCode.getTokenBefore(firstSpecifier),
                last = sourceCode.getTokenAfter(lastSpecifier, astUtils.isNotCommaToken),
                second = sourceCode.getTokenAfter(first, { includeComments: true }),
                penultimate = sourceCode.getTokenBefore(last, { includeComments: true });

            validateBraceSpacing(node, first, second, penultimate, last);
        }

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

        return {

            // var {x} = y;
            ObjectPattern: checkForObject,

            // var y = {x: 'y'}
            ObjectExpression: checkForObject,

            // import {y} from 'x';
            ImportDeclaration: checkForImport,

            // export {name} from 'yo';
            ExportNamedDeclaration: checkForExport
        };

    }
};


code:
/**
 * @fileoverview Rule to enforce placing object properties on separate lines.
 * @author Vitor Balocco
 * @deprecated in ESLint v8.53.0
 */

"use strict";

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

/** @type {import('../shared/types').Rule} */
module.exports = {
    meta: {
        deprecated: true,
        replacedBy: [],
        type: "layout",

        docs: {
            description: "Enforce placing object properties on separate lines",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/object-property-newline"
        },

        schema: [
            {
                type: "object",
                properties: {
                    allowAllPropertiesOnSameLine: {
                        type: "boolean",
                        default: false
                    },
                    allowMultiplePropertiesPerLine: { // Deprecated
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],

        fixable: "whitespace",

        messages: {
            propertiesOnNewlineAll: "Object properties must go on a new line if they aren't all on the same line.",
            propertiesOnNewline: "Object properties must go on a new line."
        }
    },

    create(context) {
        const allowSameLine = context.options[0] && (
            (context.options[0].allowAllPropertiesOnSameLine || context.options[0].allowMultiplePropertiesPerLine /* Deprecated */)
        );
        const messageId = allowSameLine
            ? "propertiesOnNewlineAll"
            : "propertiesOnNewline";

        const sourceCode = context.sourceCode;

        return {
            ObjectExpression(node) {
                if (allowSameLine) {
                    if (node.properties.length > 1) {
                        const firstTokenOfFirstProperty = sourceCode.getFirstToken(node.properties[0]);
                        const lastTokenOfLastProperty = sourceCode.getLastToken(node.properties[node.properties.length - 1]);

                        if (firstTokenOfFirstProperty.loc.end.line === lastTokenOfLastProperty.loc.start.line) {

                            // All keys and values are on the same line
                            return;
                        }
                    }
                }

                for (let i = 1; i < node.properties.length; i++) {
                    const lastTokenOfPreviousProperty = sourceCode.getLastToken(node.properties[i - 1]);
                    const firstTokenOfCurrentProperty = sourceCode.getFirstToken(node.properties[i]);

                    if (lastTokenOfPreviousProperty.loc.end.line === firstTokenOfCurrentProperty.loc.start.line) {
                        context.report({
                            node,
                            loc: firstTokenOfCurrentProperty.loc,
                            messageId,
                            fix(fixer) {
                                const comma = sourceCode.getTokenBefore(firstTokenOfCurrentProperty);
                                const rangeAfterComma = [comma.range[1], firstTokenOfCurrentProperty.range[0]];

                                // Don't perform a fix if there are any comments between the comma and the next property.
                                if (sourceCode.text.slice(rangeAfterComma[0], rangeAfterComma[1]).trim()) {
                                    return null;
                                }

                                return fixer.replaceTextRange(rangeAfterComma, "\n");
                            }
                        });
                    }
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to enforce concise object methods and properties.
 * @author Jamund Ferguson
 */

"use strict";

const OPTIONS = {
    always: "always",
    never: "never",
    methods: "methods",
    properties: "properties",
    consistent: "consistent",
    consistentAsNeeded: "consistent-as-needed"
};

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

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

        docs: {
            description: "Require or disallow method and property shorthand syntax for object literals",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/object-shorthand"
        },

        fixable: "code",

        schema: {
            anyOf: [
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods", "properties", "never", "consistent", "consistent-as-needed"]
                        }
                    ],
                    minItems: 0,
                    maxItems: 1
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods", "properties"]
                        },
                        {
                            type: "object",
                            properties: {
                                avoidQuotes: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                },
                {
                    type: "array",
                    items: [
                        {
                            enum: ["always", "methods"]
                        },
                        {
                            type: "object",
                            properties: {
                                ignoreConstructors: {
                                    type: "boolean"
                                },
                                methodsIgnorePattern: {
                                    type: "string"
                                },
                                avoidQuotes: {
                                    type: "boolean"
                                },
                                avoidExplicitReturnArrows: {
                                    type: "boolean"
                                }
                            },
                            additionalProperties: false
                        }
                    ],
                    minItems: 0,
                    maxItems: 2
                }
            ]
        },

        messages: {
            expectedAllPropertiesShorthanded: "Expected shorthand for all properties.",
            expectedLiteralMethodLongform: "Expected longform method syntax for string literal keys.",
            expectedPropertyShorthand: "Expected property shorthand.",
            expectedPropertyLongform: "Expected longform property syntax.",
            expectedMethodShorthand: "Expected method shorthand.",
            expectedMethodLongform: "Expected longform method syntax.",
            unexpectedMix: "Unexpected mix of shorthand and non-shorthand properties."
        }
    },

    create(context) {
        const APPLY = context.options[0] || OPTIONS.always;
        const APPLY_TO_METHODS = APPLY === OPTIONS.methods || APPLY === OPTIONS.always;
        const APPLY_TO_PROPS = APPLY === OPTIONS.properties || APPLY === OPTIONS.always;
        const APPLY_NEVER = APPLY === OPTIONS.never;
        const APPLY_CONSISTENT = APPLY === OPTIONS.consistent;
        const APPLY_CONSISTENT_AS_NEEDED = APPLY === OPTIONS.consistentAsNeeded;

        const PARAMS = context.options[1] || {};
        const IGNORE_CONSTRUCTORS = PARAMS.ignoreConstructors;
        const METHODS_IGNORE_PATTERN = PARAMS.methodsIgnorePattern
            ? new RegExp(PARAMS.methodsIgnorePattern, "u")
            : null;
        const AVOID_QUOTES = PARAMS.avoidQuotes;
        const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
        const sourceCode = context.sourceCode;

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

        const CTOR_PREFIX_REGEX = /[^_$0-9]/u;

        /**
         * Determines if the first character of the name is a capital letter.
         * @param {string} name The name of the node to evaluate.
         * @returns {boolean} True if the first character of the property name is a capital letter, false if not.
         * @private
         */
        function isConstructor(name) {
            const match = CTOR_PREFIX_REGEX.exec(name);

            // Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
            if (!match) {
                return false;
            }

            const firstChar = name.charAt(match.index);

            return firstChar === firstChar.toUpperCase();
        }

        /**
         * Determines if the property can have a shorthand form.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the property can have a shorthand form
         * @private
         */
        function canHaveShorthand(property) {
            return (property.kind !== "set" && property.kind !== "get" && property.type !== "SpreadElement" && property.type !== "SpreadProperty" && property.type !== "ExperimentalSpreadProperty");
        }

        /**
         * Checks whether a node is a string literal.
         * @param {ASTNode} node Any AST node.
         * @returns {boolean} `true` if it is a string literal.
         */
        function isStringLiteral(node) {
            return node.type === "Literal" && typeof node.value === "string";
        }

        /**
         * Determines if the property is a shorthand or not.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the property is considered shorthand, false if not.
         * @private
         */
        function isShorthand(property) {

            // property.method is true when `{a(){}}`.
            return (property.shorthand || property.method);
        }

        /**
         * Determines if the property's key and method or value are named equally.
         * @param {ASTNode} property Property AST node
         * @returns {boolean} True if the key and value are named equally, false if not.
         * @private
         */
        function isRedundant(property) {
            const value = property.value;

            if (value.type === "FunctionExpression") {
                return !value.id; // Only anonymous should be shorthand method.
            }
            if (value.type === "Identifier") {
                return astUtils.getStaticPropertyName(property) === value.name;
            }

            return false;
        }

        /**
         * Ensures that an object's properties are consistently shorthand, or not shorthand at all.
         * @param {ASTNode} node Property AST node
         * @param {boolean} checkRedundancy Whether to check longform redundancy
         * @returns {void}
         */
        function checkConsistency(node, checkRedundancy) {

            // We are excluding getters/setters and spread properties as they are considered neither longform nor shorthand.
            const properties = node.properties.filter(canHaveShorthand);

            // Do we still have properties left after filtering the getters and setters?
            if (properties.length > 0) {
                const shorthandProperties = properties.filter(isShorthand);

                /*
                 * If we do not have an equal number of longform properties as
                 * shorthand properties, we are using the annotations inconsistently
                 */
                if (shorthandProperties.length !== properties.length) {

                    // We have at least 1 shorthand property
                    if (shorthandProperties.length > 0) {
                        context.report({ node, messageId: "unexpectedMix" });
                    } else if (checkRedundancy) {

                        /*
                         * If all properties of the object contain a method or value with a name matching it's key,
                         * all the keys are redundant.
                         */
                        const canAlwaysUseShorthand = properties.every(isRedundant);

                        if (canAlwaysUseShorthand) {
                            context.report({ node, messageId: "expectedAllPropertiesShorthanded" });
                        }
                    }
                }
            }
        }

        /**
         * Fixes a FunctionExpression node by making it into a shorthand property.
         * @param {SourceCodeFixer} fixer The fixer object
         * @param {ASTNode} node A `Property` node that has a `FunctionExpression` or `ArrowFunctionExpression` as its value
         * @returns {Object} A fix for this node
         */
        function makeFunctionShorthand(fixer, node) {
            const firstKeyToken = node.computed
                ? sourceCode.getFirstToken(node, astUtils.isOpeningBracketToken)
                : sourceCode.getFirstToken(node.key);
            const lastKeyToken = node.computed
                ? sourceCode.getFirstTokenBetween(node.key, node.value, astUtils.isClosingBracketToken)
                : sourceCode.getLastToken(node.key);
            const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
            let keyPrefix = "";

            // key: /* */ () => {}
            if (sourceCode.commentsExistBetween(lastKeyToken, node.value)) {
                return null;
            }

            if (node.value.async) {
                keyPrefix += "async ";
            }
            if (node.value.generator) {
                keyPrefix += "*";
            }

            const fixRange = [firstKeyToken.range[0], node.range[1]];
            const methodPrefix = keyPrefix + keyText;

            if (node.value.type === "FunctionExpression") {
                const functionToken = sourceCode.getTokens(node.value).find(token => token.type === "Keyword" && token.value === "function");
                const tokenBeforeParams = node.value.generator ? sourceCode.getTokenAfter(functionToken) : functionToken;

                return fixer.replaceTextRange(
                    fixRange,
                    methodPrefix + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1])
                );
            }

            const arrowToken = sourceCode.getTokenBefore(node.value.body, astUtils.isArrowToken);
            const fnBody = sourceCode.text.slice(arrowToken.range[1], node.value.range[1]);

            let shouldAddParensAroundParameters = false;
            let tokenBeforeParams;

            if (node.value.params.length === 0) {
                tokenBeforeParams = sourceCode.getFirstToken(node.value, astUtils.isOpeningParenToken);
            } else {
                tokenBeforeParams = sourceCode.getTokenBefore(node.value.params[0]);
            }

            if (node.value.params.length === 1) {
                const hasParen = astUtils.isOpeningParenToken(tokenBeforeParams);
                const isTokenOutsideNode = tokenBeforeParams.range[0] < node.range[0];

                shouldAddParensAroundParameters = !hasParen || isTokenOutsideNode;
            }

            const sliceStart = shouldAddParensAroundParameters
                ? node.value.params[0].range[0]
                : tokenBeforeParams.range[0];
            const sliceEnd = sourceCode.getTokenBefore(arrowToken).range[1];

            const oldParamText = sourceCode.text.slice(sliceStart, sliceEnd);
            const newParamText = shouldAddParensAroundParameters ? `(${oldParamText})` : oldParamText;

            return fixer.replaceTextRange(
                fixRange,
                methodPrefix + newParamText + fnBody
            );

        }

        /**
         * Fixes a FunctionExpression node by making it into a longform property.
         * @param {SourceCodeFixer} fixer The fixer object
         * @param {ASTNode} node A `Property` node that has a `FunctionExpression` as its value
         * @returns {Object} A fix for this node
         */
        function makeFunctionLongform(fixer, node) {
            const firstKeyToken = node.computed ? sourceCode.getTokens(node).find(token => token.value === "[") : sourceCode.getFirstToken(node.key);
            const lastKeyToken = node.computed ? sourceCode.getTokensBetween(node.key, node.value).find(token => token.value === "]") : sourceCode.getLastToken(node.key);
            const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
            let functionHeader = "function";

            if (node.value.async) {
                functionHeader = `async ${functionHeader}`;
            }
            if (node.value.generator) {
                functionHeader = `${functionHeader}*`;
            }

            return fixer.replaceTextRange([node.range[0], lastKeyToken.range[1]], `${keyText}: ${functionHeader}`);
        }

        /*
         * To determine whether a given arrow function has a lexical identifier (`this`, `arguments`, `super`, or `new.target`),
         * create a stack of functions that define these identifiers (i.e. all functions except arrow functions) as the AST is
         * traversed. Whenever a new function is encountered, create a new entry on the stack (corresponding to a different lexical
         * scope of `this`), and whenever a function is exited, pop that entry off the stack. When an arrow function is entered,
         * keep a reference to it on the current stack entry, and remove that reference when the arrow function is exited.
         * When a lexical identifier is encountered, mark all the arrow functions on the current stack entry by adding them
         * to an `arrowsWithLexicalIdentifiers` set. Any arrow function in that set will not be reported by this rule,
         * because converting it into a method would change the value of one of the lexical identifiers.
         */
        const lexicalScopeStack = [];
        const arrowsWithLexicalIdentifiers = new WeakSet();
        const argumentsIdentifiers = new WeakSet();

        /**
         * Enters a function. This creates a new lexical identifier scope, so a new Set of arrow functions is pushed onto the stack.
         * Also, this marks all `arguments` identifiers so that they can be detected later.
         * @param {ASTNode} node The node representing the function.
         * @returns {void}
         */
        function enterFunction(node) {
            lexicalScopeStack.unshift(new Set());
            sourceCode.getScope(node).variables.filter(variable => variable.name === "arguments").forEach(variable => {
                variable.references.map(ref => ref.identifier).forEach(identifier => argumentsIdentifiers.add(identifier));
            });
        }

        /**
         * Exits a function. This pops the current set of arrow functions off the lexical scope stack.
         * @returns {void}
         */
        function exitFunction() {
            lexicalScopeStack.shift();
        }

        /**
         * Marks the current function as having a lexical keyword. This implies that all arrow functions
         * in the current lexical scope contain a reference to this lexical keyword.
         * @returns {void}
         */
        function reportLexicalIdentifier() {
            lexicalScopeStack[0].forEach(arrowFunction => arrowsWithLexicalIdentifiers.add(arrowFunction));
        }

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

        return {
            Program: enterFunction,
            FunctionDeclaration: enterFunction,
            FunctionExpression: enterFunction,
            "Program:exit": exitFunction,
            "FunctionDeclaration:exit": exitFunction,
            "FunctionExpression:exit": exitFunction,

            ArrowFunctionExpression(node) {
                lexicalScopeStack[0].add(node);
            },
            "ArrowFunctionExpression:exit"(node) {
                lexicalScopeStack[0].delete(node);
            },

            ThisExpression: reportLexicalIdentifier,
            Super: reportLexicalIdentifier,
            MetaProperty(node) {
                if (node.meta.name === "new" && node.property.name === "target") {
                    reportLexicalIdentifier();
                }
            },
            Identifier(node) {
                if (argumentsIdentifiers.has(node)) {
                    reportLexicalIdentifier();
                }
            },

            ObjectExpression(node) {
                if (APPLY_CONSISTENT) {
                    checkConsistency(node, false);
                } else if (APPLY_CONSISTENT_AS_NEEDED) {
                    checkConsistency(node, true);
                }
            },

            "Property:exit"(node) {
                const isConciseProperty = node.method || node.shorthand;

                // Ignore destructuring assignment
                if (node.parent.type === "ObjectPattern") {
                    return;
                }

                // getters and setters are ignored
                if (node.kind === "get" || node.kind === "set") {
                    return;
                }

                // only computed methods can fail the following checks
                if (node.computed && node.value.type !== "FunctionExpression" && node.value.type !== "ArrowFunctionExpression") {
                    return;
                }

                //--------------------------------------------------------------
                // Checks for property/method shorthand.
                if (isConciseProperty) {
                    if (node.method && (APPLY_NEVER || AVOID_QUOTES && isStringLiteral(node.key))) {
                        const messageId = APPLY_NEVER ? "expectedMethodLongform" : "expectedLiteralMethodLongform";

                        // { x() {} } should be written as { x: function() {} }
                        context.report({
                            node,
                            messageId,
                            fix: fixer => makeFunctionLongform(fixer, node)
                        });
                    } else if (APPLY_NEVER) {

                        // { x } should be written as { x: x }
                        context.report({
                            node,
                            messageId: "expectedPropertyLongform",
                            fix: fixer => fixer.insertTextAfter(node.key, `: ${node.key.name}`)
                        });
                    }
                } else if (APPLY_TO_METHODS && !node.value.id && (node.value.type === "FunctionExpression" || node.value.type === "ArrowFunctionExpression")) {
                    if (IGNORE_CONSTRUCTORS && node.key.type === "Identifier" && isConstructor(node.key.name)) {
                        return;
                    }

                    if (METHODS_IGNORE_PATTERN) {
                        const propertyName = astUtils.getStaticPropertyName(node);

                        if (propertyName !== null && METHODS_IGNORE_PATTERN.test(propertyName)) {
                            return;
                        }
                    }

                    if (AVOID_QUOTES && isStringLiteral(node.key)) {
                        return;
                    }

                    // {[x]: function(){}} should be written as {[x]() {}}
                    if (node.value.type === "FunctionExpression" ||
                        node.value.type === "ArrowFunctionExpression" &&
                        node.value.body.type === "BlockStatement" &&
                        AVOID_EXPLICIT_RETURN_ARROWS &&
                        !arrowsWithLexicalIdentifiers.has(node.value)
                    ) {
                        context.report({
                            node,
                            messageId: "expectedMethodShorthand",
                            fix: fixer => makeFunctionShorthand(fixer, node)
                        });
                    }
                } else if (node.value.type === "Identifier" && node.key.name === node.value.name && APPLY_TO_PROPS) {

                    // {x: x} should be written as {x}
                    context.report({
                        node,
                        messageId: "expectedPropertyShorthand",
                        fix(fixer) {
                            return fixer.replaceText(node, node.value.name);
                        }
                    });
                } else if (node.value.type === "Identifier" && node.key.type === "Literal" && node.key.value === node.value.name && APPLY_TO_PROPS) {
                    if (AVOID_QUOTES) {
                        return;
                    }

                    // {"x": x} should be written as {x}
                    context.report({
                        node,
                        messageId: "expectedPropertyShorthand",
                        fix(fixer) {
                            return fixer.replaceText(node, node.value.name);
                        }
                    });
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Rule to check multiple var declarations per line
 * @author Alberto Rodríguez
 * @deprecated in ESLint v8.53.0
 */
"use strict";

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

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

        docs: {
            description: "Require or disallow newlines around variable declarations",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/one-var-declaration-per-line"
        },

        schema: [
            {
                enum: ["always", "initializations"]
            }
        ],

        fixable: "whitespace",

        messages: {
            expectVarOnNewline: "Expected variable declaration to be on a new line."
        }
    },

    create(context) {

        const always = context.options[0] === "always";

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

        /**
         * Determine if provided keyword is a variant of for specifiers
         * @private
         * @param {string} keyword keyword to test
         * @returns {boolean} True if `keyword` is a variant of for specifier
         */
        function isForTypeSpecifier(keyword) {
            return keyword === "ForStatement" || keyword === "ForInStatement" || keyword === "ForOfStatement";
        }

        /**
         * Checks newlines around variable declarations.
         * @private
         * @param {ASTNode} node `VariableDeclaration` node to test
         * @returns {void}
         */
        function checkForNewLine(node) {
            if (isForTypeSpecifier(node.parent.type)) {
                return;
            }

            const declarations = node.declarations;
            let prev;

            declarations.forEach(current => {
                if (prev && prev.loc.end.line === current.loc.start.line) {
                    if (always || prev.init || current.init) {
                        context.report({
                            node,
                            messageId: "expectVarOnNewline",
                            loc: current.loc,
                            fix: fixer => fixer.insertTextBefore(current, "\n")
                        });
                    }
                }
                prev = current;
            });
        }

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

        return {
            VariableDeclaration: checkForNewLine
        };

    }
};