code:
/**
 * @fileoverview Helper class to aid in constructing fix commands.
 * @author Alan Pierce
 */
"use strict";

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

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

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

/**
 * A helper class to combine fix options into a fix command. Currently, it
 * exposes some "retain" methods that extend the range of the text being
 * replaced so that other fixes won't touch that region in the same pass.
 */
class FixTracker {

    /**
     * Create a new FixTracker.
     * @param {ruleFixer} fixer A ruleFixer instance.
     * @param {SourceCode} sourceCode A SourceCode object for the current code.
     */
    constructor(fixer, sourceCode) {
        this.fixer = fixer;
        this.sourceCode = sourceCode;
        this.retainedRange = null;
    }

    /**
     * Mark the given range as "retained", meaning that other fixes may not
     * may not modify this region in the same pass.
     * @param {int[]} range The range to retain.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainRange(range) {
        this.retainedRange = range;
        return this;
    }

    /**
     * Given a node, find the function containing it (or the entire program) and
     * mark it as retained, meaning that other fixes may not modify it in this
     * pass. This is useful for avoiding conflicts in fixes that modify control
     * flow.
     * @param {ASTNode} node The node to use as a starting point.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainEnclosingFunction(node) {
        const functionNode = astUtils.getUpperFunction(node);

        return this.retainRange(functionNode ? functionNode.range : this.sourceCode.ast.range);
    }

    /**
     * Given a node or token, find the token before and afterward, and mark that
     * range as retained, meaning that other fixes may not modify it in this
     * pass. This is useful for avoiding conflicts in fixes that make a small
     * change to the code where the AST should not be changed.
     * @param {ASTNode|Token} nodeOrToken The node or token to use as a starting
     *      point. The token to the left and right are use in the range.
     * @returns {FixTracker} The same RuleFixer, for chained calls.
     */
    retainSurroundingTokens(nodeOrToken) {
        const tokenBefore = this.sourceCode.getTokenBefore(nodeOrToken) || nodeOrToken;
        const tokenAfter = this.sourceCode.getTokenAfter(nodeOrToken) || nodeOrToken;

        return this.retainRange([tokenBefore.range[0], tokenAfter.range[1]]);
    }

    /**
     * Create a fix command that replaces the given range with the given text,
     * accounting for any retained ranges.
     * @param {int[]} range The range to remove in the fix.
     * @param {string} text The text to insert in place of the range.
     * @returns {Object} The fix command.
     */
    replaceTextRange(range, text) {
        let actualRange;

        if (this.retainedRange) {
            actualRange = [
                Math.min(this.retainedRange[0], range[0]),
                Math.max(this.retainedRange[1], range[1])
            ];
        } else {
            actualRange = range;
        }

        return this.fixer.replaceTextRange(
            actualRange,
            this.sourceCode.text.slice(actualRange[0], range[0]) +
                text +
                this.sourceCode.text.slice(range[1], actualRange[1])
        );
    }

    /**
     * Create a fix command that removes the given node or token, accounting for
     * any retained ranges.
     * @param {ASTNode|Token} nodeOrToken The node or token to remove.
     * @returns {Object} The fix command.
     */
    remove(nodeOrToken) {
        return this.replaceTextRange(nodeOrToken.range, "");
    }
}

module.exports = FixTracker;


code:
/**
 * @fileoverview A shared list of ES3 keywords.
 * @author Josh Perez
 */
"use strict";

module.exports = [
    "abstract",
    "boolean",
    "break",
    "byte",
    "case",
    "catch",
    "char",
    "class",
    "const",
    "continue",
    "debugger",
    "default",
    "delete",
    "do",
    "double",
    "else",
    "enum",
    "export",
    "extends",
    "false",
    "final",
    "finally",
    "float",
    "for",
    "function",
    "goto",
    "if",
    "implements",
    "import",
    "in",
    "instanceof",
    "int",
    "interface",
    "long",
    "native",
    "new",
    "null",
    "package",
    "private",
    "protected",
    "public",
    "return",
    "short",
    "static",
    "super",
    "switch",
    "synchronized",
    "this",
    "throw",
    "throws",
    "transient",
    "true",
    "try",
    "typeof",
    "var",
    "void",
    "volatile",
    "while",
    "with"
];

license: mit


code:
/**
 * @fileoverview `Map` to load rules lazily.
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

const debug = require("debug")("eslint:rules");

/** @typedef {import("./types").Rule} Rule */

/**
 * The `Map` object that loads each rule when it's accessed.
 * @example
 * const rules = new LazyLoadingRuleMap([
 *     ["eqeqeq", () => require("eqeqeq")],
 *     ["semi", () => require("semi")],
 *     ["no-unused-vars", () => require("no-unused-vars")]
 * ]);
 *
 * rules.get("semi"); // call `() => require("semi")` here.
 *
 * @extends {Map<string, () => Rule>}
 */
class LazyLoadingRuleMap extends Map {

    /**
     * Initialize this map.
     * @param {Array<[string, function(): Rule]>} loaders The rule loaders.
     */
    constructor(loaders) {
        let remaining = loaders.length;

        super(
            debug.enabled
                ? loaders.map(([ruleId, load]) => {
                    let cache = null;

                    return [
                        ruleId,
                        () => {
                            if (!cache) {
                                debug("Loading rule %o (remaining=%d)", ruleId, --remaining);
                                cache = load();
                            }
                            return cache;
                        }
                    ];
                })
                : loaders
        );

        // `super(...iterable)` uses `this.set()`, so disable it here.
        Object.defineProperty(LazyLoadingRuleMap.prototype, "set", {
            configurable: true,
            value: void 0
        });
    }

    /**
     * Get a rule.
     * Each rule will be loaded on the first access.
     * @param {string} ruleId The rule ID to get.
     * @returns {Rule|undefined} The rule.
     */
    get(ruleId) {
        const load = super.get(ruleId);

        return load && load();
    }

    /**
     * Iterate rules.
     * @returns {IterableIterator<Rule>} Rules.
     */
    *values() {
        for (const load of super.values()) {
            yield load();
        }
    }

    /**
     * Iterate rules.
     * @returns {IterableIterator<[string, Rule]>} Rules.
     */
    *entries() {
        for (const [ruleId, load] of super.entries()) {
            yield [ruleId, load()];
        }
    }

    /**
     * Call a function with each rule.
     * @param {Function} callbackFn The callback function.
     * @param {any} [thisArg] The object to pass to `this` of the callback function.
     * @returns {void}
     */
    forEach(callbackFn, thisArg) {
        for (const [ruleId, load] of super.entries()) {
            callbackFn.call(thisArg, load(), ruleId, this);
        }
    }
}

// Forbid mutation.
Object.defineProperties(LazyLoadingRuleMap.prototype, {
    clear: { configurable: true, value: void 0 },
    delete: { configurable: true, value: void 0 },
    [Symbol.iterator]: {
        configurable: true,
        writable: true,
        value: LazyLoadingRuleMap.prototype.entries
    }
});

module.exports = { LazyLoadingRuleMap };


code:
/**
 * @fileoverview Common utils for regular expressions.
 * @author Josh Goldberg
 * @author Toru Nagashima
 */

"use strict";

const { RegExpValidator } = require("@eslint-community/regexpp");

const REGEXPP_LATEST_ECMA_VERSION = 2024;

/**
 * Checks if the given regular expression pattern would be valid with the `u` flag.
 * @param {number} ecmaVersion ECMAScript version to parse in.
 * @param {string} pattern The regular expression pattern to verify.
 * @returns {boolean} `true` if the pattern would be valid with the `u` flag.
 * `false` if the pattern would be invalid with the `u` flag or the configured
 * ecmaVersion doesn't support the `u` flag.
 */
function isValidWithUnicodeFlag(ecmaVersion, pattern) {
    if (ecmaVersion <= 5) { // ecmaVersion <= 5 doesn't support the 'u' flag
        return false;
    }

    const validator = new RegExpValidator({
        ecmaVersion: Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION)
    });

    try {
        validator.validatePattern(pattern, void 0, void 0, { unicode: /* uFlag = */ true });
    } catch {
        return false;
    }

    return true;
}

module.exports = {
    isValidWithUnicodeFlag,
    REGEXPP_LATEST_ECMA_VERSION
};


code:
/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

module.exports = {
    isCombiningCharacter: require("./is-combining-character"),
    isEmojiModifier: require("./is-emoji-modifier"),
    isRegionalIndicatorSymbol: require("./is-regional-indicator-symbol"),
    isSurrogatePair: require("./is-surrogate-pair")
};


code:
/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

/**
 * Check whether a given character is a combining mark or not.
 * @param {number} codePoint The character code to check.
 * @returns {boolean} `true` if the character belongs to the category, any of `Mc`, `Me`, and `Mn`.
 */
module.exports = function isCombiningCharacter(codePoint) {
    return /^[\p{Mc}\p{Me}\p{Mn}]$/u.test(String.fromCodePoint(codePoint));
};


code:
/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

/**
 * Check whether a given character is an emoji modifier.
 * @param {number} code The character code to check.
 * @returns {boolean} `true` if the character is an emoji modifier.
 */
module.exports = function isEmojiModifier(code) {
    return code >= 0x1F3FB && code <= 0x1F3FF;
};


code:
/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

/**
 * Check whether a given character is a regional indicator symbol.
 * @param {number} code The character code to check.
 * @returns {boolean} `true` if the character is a regional indicator symbol.
 */
module.exports = function isRegionalIndicatorSymbol(code) {
    return code >= 0x1F1E6 && code <= 0x1F1FF;
};


code:
/**
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

/**
 * Check whether given two characters are a surrogate pair.
 * @param {number} lead The code of the lead character.
 * @param {number} tail The code of the tail character.
 * @returns {boolean} `true` if the character pair is a surrogate pair.
 */
module.exports = function isSurrogatePair(lead, tail) {
    return lead >= 0xD800 && lead < 0xDC00 && tail >= 0xDC00 && tail < 0xE000;
};


code:
/**
 * @fileoverview Validates JSDoc comments are syntactically correct
 * @author Nicholas C. Zakas
 * @deprecated in ESLint v5.10.0
 */
"use strict";

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

const doctrine = require("doctrine");

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

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

        docs: {
            description: "Enforce valid JSDoc comments",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/valid-jsdoc"
        },

        schema: [
            {
                type: "object",
                properties: {
                    prefer: {
                        type: "object",
                        additionalProperties: {
                            type: "string"
                        }
                    },
                    preferType: {
                        type: "object",
                        additionalProperties: {
                            type: "string"
                        }
                    },
                    requireReturn: {
                        type: "boolean",
                        default: true
                    },
                    requireParamDescription: {
                        type: "boolean",
                        default: true
                    },
                    requireReturnDescription: {
                        type: "boolean",
                        default: true
                    },
                    matchDescription: {
                        type: "string"
                    },
                    requireReturnType: {
                        type: "boolean",
                        default: true
                    },
                    requireParamType: {
                        type: "boolean",
                        default: true
                    }
                },
                additionalProperties: false
            }
        ],

        fixable: "code",
        messages: {
            unexpectedTag: "Unexpected @{{title}} tag; function has no return statement.",
            expected: "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.",
            use: "Use @{{name}} instead.",
            useType: "Use '{{expectedTypeName}}' instead of '{{currentTypeName}}'.",
            syntaxError: "JSDoc syntax error.",
            missingBrace: "JSDoc type missing brace.",
            missingParamDesc: "Missing JSDoc parameter description for '{{name}}'.",
            missingParamType: "Missing JSDoc parameter type for '{{name}}'.",
            missingReturnType: "Missing JSDoc return type.",
            missingReturnDesc: "Missing JSDoc return description.",
            missingReturn: "Missing JSDoc @{{returns}} for function.",
            missingParam: "Missing JSDoc for parameter '{{name}}'.",
            duplicateParam: "Duplicate JSDoc parameter '{{name}}'.",
            unsatisfiedDesc: "JSDoc description does not satisfy the regex pattern."
        },

        deprecated: true,
        replacedBy: []
    },

    create(context) {

        const options = context.options[0] || {},
            prefer = options.prefer || {},
            sourceCode = context.sourceCode,

            // these both default to true, so you have to explicitly make them false
            requireReturn = options.requireReturn !== false,
            requireParamDescription = options.requireParamDescription !== false,
            requireReturnDescription = options.requireReturnDescription !== false,
            requireReturnType = options.requireReturnType !== false,
            requireParamType = options.requireParamType !== false,
            preferType = options.preferType || {},
            checkPreferType = Object.keys(preferType).length !== 0;

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

        // Using a stack to store if a function returns or not (handling nested functions)
        const fns = [];

        /**
         * Check if node type is a Class
         * @param {ASTNode} node node to check.
         * @returns {boolean} True is its a class
         * @private
         */
        function isTypeClass(node) {
            return node.type === "ClassExpression" || node.type === "ClassDeclaration";
        }

        /**
         * When parsing a new function, store it in our function stack.
         * @param {ASTNode} node A function node to check.
         * @returns {void}
         * @private
         */
        function startFunction(node) {
            fns.push({
                returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") ||
                    isTypeClass(node) || node.async
            });
        }

        /**
         * Indicate that return has been found in the current function.
         * @param {ASTNode} node The return node.
         * @returns {void}
         * @private
         */
        function addReturn(node) {
            const functionState = fns[fns.length - 1];

            if (functionState && node.argument !== null) {
                functionState.returnPresent = true;
            }
        }

        /**
         * Check if return tag type is void or undefined
         * @param {Object} tag JSDoc tag
         * @returns {boolean} True if its of type void or undefined
         * @private
         */
        function isValidReturnType(tag) {
            return tag.type === null || tag.type.name === "void" || tag.type.type === "UndefinedLiteral";
        }

        /**
         * Check if type should be validated based on some exceptions
         * @param {Object} type JSDoc tag
         * @returns {boolean} True if it can be validated
         * @private
         */
        function canTypeBeValidated(type) {
            return type !== "UndefinedLiteral" && // {undefined} as there is no name property available.
                   type !== "NullLiteral" && // {null}
                   type !== "NullableLiteral" && // {?}
                   type !== "FunctionType" && // {function(a)}
                   type !== "AllLiteral"; // {*}
        }

        /**
         * Extract the current and expected type based on the input type object
         * @param {Object} type JSDoc tag
         * @returns {{currentType: Doctrine.Type, expectedTypeName: string}} The current type annotation and
         * the expected name of the annotation
         * @private
         */
        function getCurrentExpectedTypes(type) {
            let currentType;

            if (type.name) {
                currentType = type;
            } else if (type.expression) {
                currentType = type.expression;
            }

            return {
                currentType,
                expectedTypeName: currentType && preferType[currentType.name]
            };
        }

        /**
         * Gets the location of a JSDoc node in a file
         * @param {Token} jsdocComment The comment that this node is parsed from
         * @param {{range: number[]}} parsedJsdocNode A tag or other node which was parsed from this comment
         * @returns {{start: SourceLocation, end: SourceLocation}} The 0-based source location for the tag
         */
        function getAbsoluteRange(jsdocComment, parsedJsdocNode) {
            return {
                start: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[0]),
                end: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[1])
            };
        }

        /**
         * Validate type for a given JSDoc node
         * @param {Object} jsdocNode JSDoc node
         * @param {Object} type JSDoc tag
         * @returns {void}
         * @private
         */
        function validateType(jsdocNode, type) {
            if (!type || !canTypeBeValidated(type.type)) {
                return;
            }

            const typesToCheck = [];
            let elements = [];

            switch (type.type) {
                case "TypeApplication": // {Array.<String>}
                    elements = type.applications[0].type === "UnionType" ? type.applications[0].elements : type.applications;
                    typesToCheck.push(getCurrentExpectedTypes(type));
                    break;
                case "RecordType": // {{20:String}}
                    elements = type.fields;
                    break;
                case "UnionType": // {String|number|Test}
                case "ArrayType": // {[String, number, Test]}
                    elements = type.elements;
                    break;
                case "FieldType": // Array.<{count: number, votes: number}>
                    if (type.value) {
                        typesToCheck.push(getCurrentExpectedTypes(type.value));
                    }
                    break;
                default:
                    typesToCheck.push(getCurrentExpectedTypes(type));
            }

            elements.forEach(validateType.bind(null, jsdocNode));

            typesToCheck.forEach(typeToCheck => {
                if (typeToCheck.expectedTypeName &&
                    typeToCheck.expectedTypeName !== typeToCheck.currentType.name) {
                    context.report({
                        node: jsdocNode,
                        messageId: "useType",
                        loc: getAbsoluteRange(jsdocNode, typeToCheck.currentType),
                        data: {
                            currentTypeName: typeToCheck.currentType.name,
                            expectedTypeName: typeToCheck.expectedTypeName
                        },
                        fix(fixer) {
                            return fixer.replaceTextRange(
                                typeToCheck.currentType.range.map(indexInComment => jsdocNode.range[0] + 2 + indexInComment),
                                typeToCheck.expectedTypeName
                            );
                        }
                    });
                }
            });
        }

        /**
         * Validate the JSDoc node and output warnings if anything is wrong.
         * @param {ASTNode} node The AST node to check.
         * @returns {void}
         * @private
         */
        function checkJSDoc(node) {
            const jsdocNode = sourceCode.getJSDocComment(node),
                functionData = fns.pop(),
                paramTagsByName = Object.create(null),
                paramTags = [];
            let hasReturns = false,
                returnsTag,
                hasConstructor = false,
                isInterface = false,
                isOverride = false,
                isAbstract = false;

            // make sure only to validate JSDoc comments
            if (jsdocNode) {
                let jsdoc;

                try {
                    jsdoc = doctrine.parse(jsdocNode.value, {
                        strict: true,
                        unwrap: true,
                        sloppy: true,
                        range: true
                    });
                } catch (ex) {

                    if (/braces/iu.test(ex.message)) {
                        context.report({ node: jsdocNode, messageId: "missingBrace" });
                    } else {
                        context.report({ node: jsdocNode, messageId: "syntaxError" });
                    }

                    return;
                }

                jsdoc.tags.forEach(tag => {

                    switch (tag.title.toLowerCase()) {

                        case "param":
                        case "arg":
                        case "argument":
                            paramTags.push(tag);
                            break;

                        case "return":
                        case "returns":
                            hasReturns = true;
                            returnsTag = tag;
                            break;

                        case "constructor":
                        case "class":
                            hasConstructor = true;
                            break;

                        case "override":
                        case "inheritdoc":
                            isOverride = true;
                            break;

                        case "abstract":
                        case "virtual":
                            isAbstract = true;
                            break;

                        case "interface":
                            isInterface = true;
                            break;

                        // no default
                    }

                    // check tag preferences
                    if (Object.prototype.hasOwnProperty.call(prefer, tag.title) && tag.title !== prefer[tag.title]) {
                        const entireTagRange = getAbsoluteRange(jsdocNode, tag);

                        context.report({
                            node: jsdocNode,
                            messageId: "use",
                            loc: {
                                start: entireTagRange.start,
                                end: {
                                    line: entireTagRange.start.line,
                                    column: entireTagRange.start.column + `@${tag.title}`.length
                                }
                            },
                            data: { name: prefer[tag.title] },
                            fix(fixer) {
                                return fixer.replaceTextRange(
                                    [
                                        jsdocNode.range[0] + tag.range[0] + 3,
                                        jsdocNode.range[0] + tag.range[0] + tag.title.length + 3
                                    ],
                                    prefer[tag.title]
                                );
                            }
                        });
                    }

                    // validate the types
                    if (checkPreferType && tag.type) {
                        validateType(jsdocNode, tag.type);
                    }
                });

                paramTags.forEach(param => {
                    if (requireParamType && !param.type) {
                        context.report({
                            node: jsdocNode,
                            messageId: "missingParamType",
                            loc: getAbsoluteRange(jsdocNode, param),
                            data: { name: param.name }
                        });
                    }
                    if (!param.description && requireParamDescription) {
                        context.report({
                            node: jsdocNode,
                            messageId: "missingParamDesc",
                            loc: getAbsoluteRange(jsdocNode, param),
                            data: { name: param.name }
                        });
                    }
                    if (paramTagsByName[param.name]) {
                        context.report({
                            node: jsdocNode,
                            messageId: "duplicateParam",
                            loc: getAbsoluteRange(jsdocNode, param),
                            data: { name: param.name }
                        });
                    } else if (!param.name.includes(".")) {
                        paramTagsByName[param.name] = param;
                    }
                });

                if (hasReturns) {
                    if (!requireReturn && !functionData.returnPresent && (returnsTag.type === null || !isValidReturnType(returnsTag)) && !isAbstract) {
                        context.report({
                            node: jsdocNode,
                            messageId: "unexpectedTag",
                            loc: getAbsoluteRange(jsdocNode, returnsTag),
                            data: {
                                title: returnsTag.title
                            }
                        });
                    } else {
                        if (requireReturnType && !returnsTag.type) {
                            context.report({ node: jsdocNode, messageId: "missingReturnType" });
                        }

                        if (!isValidReturnType(returnsTag) && !returnsTag.description && requireReturnDescription) {
                            context.report({ node: jsdocNode, messageId: "missingReturnDesc" });
                        }
                    }
                }

                // check for functions missing @returns
                if (!isOverride && !hasReturns && !hasConstructor && !isInterface &&
                    node.parent.kind !== "get" && node.parent.kind !== "constructor" &&
                    node.parent.kind !== "set" && !isTypeClass(node)) {
                    if (requireReturn || (functionData.returnPresent && !node.async)) {
                        context.report({
                            node: jsdocNode,
                            messageId: "missingReturn",
                            data: {
                                returns: prefer.returns || "returns"
                            }
                        });
                    }
                }

                // check the parameters
                const jsdocParamNames = Object.keys(paramTagsByName);

                if (node.params) {
                    node.params.forEach((param, paramsIndex) => {
                        const bindingParam = param.type === "AssignmentPattern"
                            ? param.left
                            : param;

                        // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
                        if (bindingParam.type === "Identifier") {
                            const name = bindingParam.name;

                            if (jsdocParamNames[paramsIndex] && (name !== jsdocParamNames[paramsIndex])) {
                                context.report({
                                    node: jsdocNode,
                                    messageId: "expected",
                                    loc: getAbsoluteRange(jsdocNode, paramTagsByName[jsdocParamNames[paramsIndex]]),
                                    data: {
                                        name,
                                        jsdocName: jsdocParamNames[paramsIndex]
                                    }
                                });
                            } else if (!paramTagsByName[name] && !isOverride) {
                                context.report({
                                    node: jsdocNode,
                                    messageId: "missingParam",
                                    data: {
                                        name
                                    }
                                });
                            }
                        }
                    });
                }

                if (options.matchDescription) {
                    const regex = new RegExp(options.matchDescription, "u");

                    if (!regex.test(jsdoc.description)) {
                        context.report({ node: jsdocNode, messageId: "unsatisfiedDesc" });
                    }
                }

            }

        }

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

        return {
            ArrowFunctionExpression: startFunction,
            FunctionExpression: startFunction,
            FunctionDeclaration: startFunction,
            ClassExpression: startFunction,
            ClassDeclaration: startFunction,
            "ArrowFunctionExpression:exit": checkJSDoc,
            "FunctionExpression:exit": checkJSDoc,
            "FunctionDeclaration:exit": checkJSDoc,
            "ClassExpression:exit": checkJSDoc,
            "ClassDeclaration:exit": checkJSDoc,
            ReturnStatement: addReturn
        };

    }
};


code:
/**
 * @fileoverview Ensures that the results of typeof are compared against a valid string
 * @author Ian Christian Myers
 */
"use strict";

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

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

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

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

        docs: {
            description: "Enforce comparing `typeof` expressions against valid strings",
            recommended: true,
            url: "https://eslint.org/docs/latest/rules/valid-typeof"
        },

        hasSuggestions: true,

        schema: [
            {
                type: "object",
                properties: {
                    requireStringLiterals: {
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],
        messages: {
            invalidValue: "Invalid typeof comparison value.",
            notString: "Typeof comparisons should be to string literals.",
            suggestString: 'Use `"{{type}}"` instead of `{{type}}`.'
        }
    },

    create(context) {

        const VALID_TYPES = new Set(["symbol", "undefined", "object", "boolean", "number", "string", "function", "bigint"]),
            OPERATORS = new Set(["==", "===", "!=", "!=="]);
        const sourceCode = context.sourceCode;
        const requireStringLiterals = context.options[0] && context.options[0].requireStringLiterals;

        let globalScope;

        /**
         * Checks whether the given node represents a reference to a global variable that is not declared in the source code.
         * These identifiers will be allowed, as it is assumed that user has no control over the names of external global variables.
         * @param {ASTNode} node `Identifier` node to check.
         * @returns {boolean} `true` if the node is a reference to a global variable.
         */
        function isReferenceToGlobalVariable(node) {
            const variable = globalScope.set.get(node.name);

            return variable && variable.defs.length === 0 &&
                variable.references.some(ref => ref.identifier === node);
        }

        /**
         * Determines whether a node is a typeof expression.
         * @param {ASTNode} node The node
         * @returns {boolean} `true` if the node is a typeof expression
         */
        function isTypeofExpression(node) {
            return node.type === "UnaryExpression" && node.operator === "typeof";
        }

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

        return {

            Program(node) {
                globalScope = sourceCode.getScope(node);
            },

            UnaryExpression(node) {
                if (isTypeofExpression(node)) {
                    const { parent } = node;

                    if (parent.type === "BinaryExpression" && OPERATORS.has(parent.operator)) {
                        const sibling = parent.left === node ? parent.right : parent.left;

                        if (sibling.type === "Literal" || astUtils.isStaticTemplateLiteral(sibling)) {
                            const value = sibling.type === "Literal" ? sibling.value : sibling.quasis[0].value.cooked;

                            if (!VALID_TYPES.has(value)) {
                                context.report({ node: sibling, messageId: "invalidValue" });
                            }
                        } else if (sibling.type === "Identifier" && sibling.name === "undefined" && isReferenceToGlobalVariable(sibling)) {
                            context.report({
                                node: sibling,
                                messageId: requireStringLiterals ? "notString" : "invalidValue",
                                suggest: [
                                    {
                                        messageId: "suggestString",
                                        data: { type: "undefined" },
                                        fix(fixer) {
                                            return fixer.replaceText(sibling, '"undefined"');
                                        }
                                    }
                                ]
                            });
                        } else if (requireStringLiterals && !isTypeofExpression(sibling)) {
                            context.report({ node: sibling, messageId: "notString" });
                        }
                    }
                }
            }

        };

    }
};


code:
/**
 * @fileoverview Rule to enforce var declarations are only at the top of a function.
 * @author Danny Fritz
 * @author Gyandeep Singh
 */
"use strict";

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

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

        docs: {
            description: "Require `var` declarations be placed at the top of their containing scope",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/vars-on-top"
        },

        schema: [],
        messages: {
            top: "All 'var' declarations must be at the top of the function scope."
        }
    },

    create(context) {

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

        /**
         * Has AST suggesting a directive.
         * @param {ASTNode} node any node
         * @returns {boolean} whether the given node structurally represents a directive
         */
        function looksLikeDirective(node) {
            return node.type === "ExpressionStatement" &&
                node.expression.type === "Literal" && typeof node.expression.value === "string";
        }

        /**
         * Check to see if its a ES6 import declaration
         * @param {ASTNode} node any node
         * @returns {boolean} whether the given node represents a import declaration
         */
        function looksLikeImport(node) {
            return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" ||
                node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier";
        }

        /**
         * Checks whether a given node is a variable declaration or not.
         * @param {ASTNode} node any node
         * @returns {boolean} `true` if the node is a variable declaration.
         */
        function isVariableDeclaration(node) {
            return (
                node.type === "VariableDeclaration" ||
                (
                    node.type === "ExportNamedDeclaration" &&
                    node.declaration &&
                    node.declaration.type === "VariableDeclaration"
                )
            );
        }

        /**
         * Checks whether this variable is on top of the block body
         * @param {ASTNode} node The node to check
         * @param {ASTNode[]} statements collection of ASTNodes for the parent node block
         * @returns {boolean} True if var is on top otherwise false
         */
        function isVarOnTop(node, statements) {
            const l = statements.length;
            let i = 0;

            // Skip over directives and imports. Static blocks don't have either.
            if (node.parent.type !== "StaticBlock") {
                for (; i < l; ++i) {
                    if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
                        break;
                    }
                }
            }

            for (; i < l; ++i) {
                if (!isVariableDeclaration(statements[i])) {
                    return false;
                }
                if (statements[i] === node) {
                    return true;
                }
            }

            return false;
        }

        /**
         * Checks whether variable is on top at the global level
         * @param {ASTNode} node The node to check
         * @param {ASTNode} parent Parent of the node
         * @returns {void}
         */
        function globalVarCheck(node, parent) {
            if (!isVarOnTop(node, parent.body)) {
                context.report({ node, messageId: "top" });
            }
        }

        /**
         * Checks whether variable is on top at functional block scope level
         * @param {ASTNode} node The node to check
         * @returns {void}
         */
        function blockScopeVarCheck(node) {
            const { parent } = node;

            if (
                parent.type === "BlockStatement" &&
                /Function/u.test(parent.parent.type) &&
                isVarOnTop(node, parent.body)
            ) {
                return;
            }

            if (
                parent.type === "StaticBlock" &&
                isVarOnTop(node, parent.body)
            ) {
                return;
            }

            context.report({ node, messageId: "top" });
        }

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

        return {
            "VariableDeclaration[kind='var']"(node) {
                if (node.parent.type === "ExportNamedDeclaration") {
                    globalVarCheck(node.parent, node.parent.parent);
                } else if (node.parent.type === "Program") {
                    globalVarCheck(node, node.parent);
                } else {
                    blockScopeVarCheck(node);
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to flag when IIFE is not wrapped in parens
 * @author Ilya Volodin
 * @deprecated in ESLint v8.53.0
 */

"use strict";

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

const astUtils = require("./utils/ast-utils");
const eslintUtils = require("@eslint-community/eslint-utils");

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

/**
 * Check if the given node is callee of a `NewExpression` node
 * @param {ASTNode} node node to check
 * @returns {boolean} True if the node is callee of a `NewExpression` node
 * @private
 */
function isCalleeOfNewExpression(node) {
    const maybeCallee = node.parent.type === "ChainExpression"
        ? node.parent
        : node;

    return (
        maybeCallee.parent.type === "NewExpression" &&
        maybeCallee.parent.callee === maybeCallee
    );
}

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

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

        docs: {
            description: "Require parentheses around immediate `function` invocations",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/wrap-iife"
        },

        schema: [
            {
                enum: ["outside", "inside", "any"]
            },
            {
                type: "object",
                properties: {
                    functionPrototypeMethods: {
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],

        fixable: "code",
        messages: {
            wrapInvocation: "Wrap an immediate function invocation in parentheses.",
            wrapExpression: "Wrap only the function expression in parens.",
            moveInvocation: "Move the invocation into the parens that contain the function."
        }
    },

    create(context) {

        const style = context.options[0] || "outside";
        const includeFunctionPrototypeMethods = context.options[1] && context.options[1].functionPrototypeMethods;

        const sourceCode = context.sourceCode;

        /**
         * Check if the node is wrapped in any (). All parens count: grouping parens and parens for constructs such as if()
         * @param {ASTNode} node node to evaluate
         * @returns {boolean} True if it is wrapped in any parens
         * @private
         */
        function isWrappedInAnyParens(node) {
            return astUtils.isParenthesised(sourceCode, node);
        }

        /**
         * Check if the node is wrapped in grouping (). Parens for constructs such as if() don't count
         * @param {ASTNode} node node to evaluate
         * @returns {boolean} True if it is wrapped in grouping parens
         * @private
         */
        function isWrappedInGroupingParens(node) {
            return eslintUtils.isParenthesized(1, node, sourceCode);
        }

        /**
         * Get the function node from an IIFE
         * @param {ASTNode} node node to evaluate
         * @returns {ASTNode} node that is the function expression of the given IIFE, or null if none exist
         */
        function getFunctionNodeFromIIFE(node) {
            const callee = astUtils.skipChainExpression(node.callee);

            if (callee.type === "FunctionExpression") {
                return callee;
            }

            if (includeFunctionPrototypeMethods &&
                callee.type === "MemberExpression" &&
                callee.object.type === "FunctionExpression" &&
                (astUtils.getStaticPropertyName(callee) === "call" || astUtils.getStaticPropertyName(callee) === "apply")
            ) {
                return callee.object;
            }

            return null;
        }

        return {
            CallExpression(node) {
                const innerNode = getFunctionNodeFromIIFE(node);

                if (!innerNode) {
                    return;
                }

                const isCallExpressionWrapped = isWrappedInAnyParens(node),
                    isFunctionExpressionWrapped = isWrappedInAnyParens(innerNode);

                if (!isCallExpressionWrapped && !isFunctionExpressionWrapped) {
                    context.report({
                        node,
                        messageId: "wrapInvocation",
                        fix(fixer) {
                            const nodeToSurround = style === "inside" ? innerNode : node;

                            return fixer.replaceText(nodeToSurround, `(${sourceCode.getText(nodeToSurround)})`);
                        }
                    });
                } else if (style === "inside" && !isFunctionExpressionWrapped) {
                    context.report({
                        node,
                        messageId: "wrapExpression",
                        fix(fixer) {

                            // The outer call expression will always be wrapped at this point.

                            if (isWrappedInGroupingParens(node) && !isCalleeOfNewExpression(node)) {

                                /*
                                 * Parenthesize the function expression and remove unnecessary grouping parens around the call expression.
                                 * Replace the range between the end of the function expression and the end of the call expression.
                                 * for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`.
                                 */

                                const parenAfter = sourceCode.getTokenAfter(node);

                                return fixer.replaceTextRange(
                                    [innerNode.range[1], parenAfter.range[1]],
                                    `)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}`
                                );
                            }

                            /*
                             * Call expression is wrapped in mandatory parens such as if(), or in necessary grouping parens.
                             * These parens cannot be removed, so just parenthesize the function expression.
                             */

                            return fixer.replaceText(innerNode, `(${sourceCode.getText(innerNode)})`);
                        }
                    });
                } else if (style === "outside" && !isCallExpressionWrapped) {
                    context.report({
                        node,
                        messageId: "moveInvocation",
                        fix(fixer) {

                            /*
                             * The inner function expression will always be wrapped at this point.
                             * It's only necessary to replace the range between the end of the function expression
                             * and the call expression. For example, in `(function(foo) {})(bar)`, the range `)(bar)`
                             * should get replaced with `(bar))`.
                             */
                            const parenAfter = sourceCode.getTokenAfter(innerNode);

                            return fixer.replaceTextRange(
                                [parenAfter.range[0], node.range[1]],
                                `${sourceCode.getText().slice(parenAfter.range[1], node.range[1])})`
                            );
                        }
                    });
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to flag when regex literals are not wrapped in parens
 * @author Matt DuVall <http://www.mattduvall.com>
 * @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: "Require parenthesis around regex literals",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/wrap-regex"
        },

        schema: [],
        fixable: "code",

        messages: {
            requireParens: "Wrap the regexp literal in parens to disambiguate the slash."
        }
    },

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

        return {

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

                if (nodeType === "RegularExpression") {
                    const beforeToken = sourceCode.getTokenBefore(node);
                    const afterToken = sourceCode.getTokenAfter(node);
                    const { parent } = node;

                    if (parent.type === "MemberExpression" && parent.object === node &&
                        !(beforeToken && beforeToken.value === "(" && afterToken && afterToken.value === ")")) {
                        context.report({
                            node,
                            messageId: "requireParens",
                            fix: fixer => fixer.replaceText(node, `(${sourceCode.getText(node)})`)
                        });
                    }
                }
            }
        };

    }
};


code:
/**
 * @fileoverview Rule to check the spacing around the * in yield* expressions.
 * @author Bryan Smith
 * @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: "Require or disallow spacing around the `*` in `yield*` expressions",
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/yield-star-spacing"
        },

        fixable: "whitespace",

        schema: [
            {
                oneOf: [
                    {
                        enum: ["before", "after", "both", "neither"]
                    },
                    {
                        type: "object",
                        properties: {
                            before: { type: "boolean" },
                            after: { type: "boolean" }
                        },
                        additionalProperties: false
                    }
                ]
            }
        ],
        messages: {
            missingBefore: "Missing space before *.",
            missingAfter: "Missing space after *.",
            unexpectedBefore: "Unexpected space before *.",
            unexpectedAfter: "Unexpected space after *."
        }
    },

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

        const mode = (function(option) {
            if (!option || typeof option === "string") {
                return {
                    before: { before: true, after: false },
                    after: { before: false, after: true },
                    both: { before: true, after: true },
                    neither: { before: false, after: false }
                }[option || "after"];
            }
            return option;
        }(context.options[0]));

        /**
         * Checks the spacing between two tokens before or after the star token.
         * @param {string} side Either "before" or "after".
         * @param {Token} leftToken `function` keyword token if side is "before", or
         *     star token if side is "after".
         * @param {Token} rightToken Star token if side is "before", or identifier
         *     token if side is "after".
         * @returns {void}
         */
        function checkSpacing(side, leftToken, rightToken) {
            if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken) !== mode[side]) {
                const after = leftToken.value === "*";
                const spaceRequired = mode[side];
                const node = after ? leftToken : rightToken;
                let messageId = "";

                if (spaceRequired) {
                    messageId = side === "before" ? "missingBefore" : "missingAfter";
                } else {
                    messageId = side === "before" ? "unexpectedBefore" : "unexpectedAfter";
                }

                context.report({
                    node,
                    messageId,
                    fix(fixer) {
                        if (spaceRequired) {
                            if (after) {
                                return fixer.insertTextAfter(node, " ");
                            }
                            return fixer.insertTextBefore(node, " ");
                        }
                        return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
                    }
                });
            }
        }

        /**
         * Enforces the spacing around the star if node is a yield* expression.
         * @param {ASTNode} node A yield expression node.
         * @returns {void}
         */
        function checkExpression(node) {
            if (!node.delegate) {
                return;
            }

            const tokens = sourceCode.getFirstTokens(node, 3);
            const yieldToken = tokens[0];
            const starToken = tokens[1];
            const nextToken = tokens[2];

            checkSpacing("before", yieldToken, starToken);
            checkSpacing("after", starToken, nextToken);
        }

        return {
            YieldExpression: checkExpression
        };

    }
};


code:
/**
 * @fileoverview Rule to require or disallow yoda comparisons
 * @author Nicholas C. Zakas
 */
"use strict";

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

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

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

/**
 * Determines whether an operator is a comparison operator.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether or not it is a comparison operator.
 */
function isComparisonOperator(operator) {
    return /^(==|===|!=|!==|<|>|<=|>=)$/u.test(operator);
}

/**
 * Determines whether an operator is an equality operator.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether or not it is an equality operator.
 */
function isEqualityOperator(operator) {
    return /^(==|===)$/u.test(operator);
}

/**
 * Determines whether an operator is one used in a range test.
 * Allowed operators are `<` and `<=`.
 * @param {string} operator The operator to check.
 * @returns {boolean} Whether the operator is used in range tests.
 */
function isRangeTestOperator(operator) {
    return ["<", "<="].includes(operator);
}

/**
 * Determines whether a non-Literal node is a negative number that should be
 * treated as if it were a single Literal node.
 * @param {ASTNode} node Node to test.
 * @returns {boolean} True if the node is a negative number that looks like a
 *                    real literal and should be treated as such.
 */
function isNegativeNumericLiteral(node) {
    return (
        node.type === "UnaryExpression" &&
        node.operator === "-" &&
        node.prefix &&
        astUtils.isNumericLiteral(node.argument)
    );
}

/**
 * Determines whether a non-Literal node should be treated as a single Literal node.
 * @param {ASTNode} node Node to test
 * @returns {boolean} True if the node should be treated as a single Literal node.
 */
function looksLikeLiteral(node) {
    return isNegativeNumericLiteral(node) || astUtils.isStaticTemplateLiteral(node);
}

/**
 * Attempts to derive a Literal node from nodes that are treated like literals.
 * @param {ASTNode} node Node to normalize.
 * @returns {ASTNode} One of the following options.
 *  1. The original node if the node is already a Literal
 *  2. A normalized Literal node with the negative number as the value if the
 *     node represents a negative number literal.
 *  3. A normalized Literal node with the string as the value if the node is
 *     a Template Literal without expression.
 *  4. Otherwise `null`.
 */
function getNormalizedLiteral(node) {
    if (node.type === "Literal") {
        return node;
    }

    if (isNegativeNumericLiteral(node)) {
        return {
            type: "Literal",
            value: -node.argument.value,
            raw: `-${node.argument.value}`
        };
    }

    if (astUtils.isStaticTemplateLiteral(node)) {
        return {
            type: "Literal",
            value: node.quasis[0].value.cooked,
            raw: node.quasis[0].value.raw
        };
    }

    return null;
}

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

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

        docs: {
            description: 'Require or disallow "Yoda" conditions',
            recommended: false,
            url: "https://eslint.org/docs/latest/rules/yoda"
        },

        schema: [
            {
                enum: ["always", "never"]
            },
            {
                type: "object",
                properties: {
                    exceptRange: {
                        type: "boolean",
                        default: false
                    },
                    onlyEquality: {
                        type: "boolean",
                        default: false
                    }
                },
                additionalProperties: false
            }
        ],

        fixable: "code",
        messages: {
            expected:
                "Expected literal to be on the {{expectedSide}} side of {{operator}}."
        }
    },

    create(context) {

        // Default to "never" (!always) if no option
        const always = context.options[0] === "always";
        const exceptRange =
            context.options[1] && context.options[1].exceptRange;
        const onlyEquality =
            context.options[1] && context.options[1].onlyEquality;

        const sourceCode = context.sourceCode;

        /**
         * Determines whether node represents a range test.
         * A range test is a "between" test like `(0 <= x && x < 1)` or an "outside"
         * test like `(x < 0 || 1 <= x)`. It must be wrapped in parentheses, and
         * both operators must be `<` or `<=`. Finally, the literal on the left side
         * must be less than or equal to the literal on the right side so that the
         * test makes any sense.
         * @param {ASTNode} node LogicalExpression node to test.
         * @returns {boolean} Whether node is a range test.
         */
        function isRangeTest(node) {
            const left = node.left,
                right = node.right;

            /**
             * Determines whether node is of the form `0 <= x && x < 1`.
             * @returns {boolean} Whether node is a "between" range test.
             */
            function isBetweenTest() {
                if (node.operator === "&&" && astUtils.isSameReference(left.right, right.left)) {
                    const leftLiteral = getNormalizedLiteral(left.left);
                    const rightLiteral = getNormalizedLiteral(right.right);

                    if (leftLiteral === null && rightLiteral === null) {
                        return false;
                    }

                    if (rightLiteral === null || leftLiteral === null) {
                        return true;
                    }

                    if (leftLiteral.value <= rightLiteral.value) {
                        return true;
                    }
                }
                return false;
            }

            /**
             * Determines whether node is of the form `x < 0 || 1 <= x`.
             * @returns {boolean} Whether node is an "outside" range test.
             */
            function isOutsideTest() {
                if (node.operator === "||" && astUtils.isSameReference(left.left, right.right)) {
                    const leftLiteral = getNormalizedLiteral(left.right);
                    const rightLiteral = getNormalizedLiteral(right.left);

                    if (leftLiteral === null && rightLiteral === null) {
                        return false;
                    }

                    if (rightLiteral === null || leftLiteral === null) {
                        return true;
                    }

                    if (leftLiteral.value <= rightLiteral.value) {
                        return true;
                    }
                }

                return false;
            }

            /**
             * Determines whether node is wrapped in parentheses.
             * @returns {boolean} Whether node is preceded immediately by an open
             *                    paren token and followed immediately by a close
             *                    paren token.
             */
            function isParenWrapped() {
                return astUtils.isParenthesised(sourceCode, node);
            }

            return (
                node.type === "LogicalExpression" &&
                left.type === "BinaryExpression" &&
                right.type === "BinaryExpression" &&
                isRangeTestOperator(left.operator) &&
                isRangeTestOperator(right.operator) &&
                (isBetweenTest() || isOutsideTest()) &&
                isParenWrapped()
            );
        }

        const OPERATOR_FLIP_MAP = {
            "===": "===",
            "!==": "!==",
            "==": "==",
            "!=": "!=",
            "<": ">",
            ">": "<",
            "<=": ">=",
            ">=": "<="
        };

        /**
         * Returns a string representation of a BinaryExpression node with its sides/operator flipped around.
         * @param {ASTNode} node The BinaryExpression node
         * @returns {string} A string representation of the node with the sides and operator flipped
         */
        function getFlippedString(node) {
            const operatorToken = sourceCode.getFirstTokenBetween(
                node.left,
                node.right,
                token => token.value === node.operator
            );
            const lastLeftToken = sourceCode.getTokenBefore(operatorToken);
            const firstRightToken = sourceCode.getTokenAfter(operatorToken);

            const source = sourceCode.getText();

            const leftText = source.slice(
                node.range[0],
                lastLeftToken.range[1]
            );
            const textBeforeOperator = source.slice(
                lastLeftToken.range[1],
                operatorToken.range[0]
            );
            const textAfterOperator = source.slice(
                operatorToken.range[1],
                firstRightToken.range[0]
            );
            const rightText = source.slice(
                firstRightToken.range[0],
                node.range[1]
            );

            const tokenBefore = sourceCode.getTokenBefore(node);
            const tokenAfter = sourceCode.getTokenAfter(node);
            let prefix = "";
            let suffix = "";

            if (
                tokenBefore &&
                tokenBefore.range[1] === node.range[0] &&
                !astUtils.canTokensBeAdjacent(tokenBefore, firstRightToken)
            ) {
                prefix = " ";
            }

            if (
                tokenAfter &&
                node.range[1] === tokenAfter.range[0] &&
                !astUtils.canTokensBeAdjacent(lastLeftToken, tokenAfter)
            ) {
                suffix = " ";
            }

            return (
                prefix +
                rightText +
                textBeforeOperator +
                OPERATOR_FLIP_MAP[operatorToken.value] +
                textAfterOperator +
                leftText +
                suffix
            );
        }

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

        return {
            BinaryExpression(node) {
                const expectedLiteral = always ? node.left : node.right;
                const expectedNonLiteral = always ? node.right : node.left;

                // If `expectedLiteral` is not a literal, and `expectedNonLiteral` is a literal, raise an error.
                if (
                    (expectedNonLiteral.type === "Literal" ||
                        looksLikeLiteral(expectedNonLiteral)) &&
                    !(
                        expectedLiteral.type === "Literal" ||
                        looksLikeLiteral(expectedLiteral)
                    ) &&
                    !(!isEqualityOperator(node.operator) && onlyEquality) &&
                    isComparisonOperator(node.operator) &&
                    !(exceptRange && isRangeTest(node.parent))
                ) {
                    context.report({
                        node,
                        messageId: "expected",
                        data: {
                            operator: node.operator,
                            expectedSide: always ? "left" : "right"
                        },
                        fix: fixer =>
                            fixer.replaceText(node, getFlippedString(node))
                    });
                }
            }
        };
    }
};


code:
/**
 * @fileoverview Common utils for AST.
 *
 * This file contains only shared items for core and rules.
 * If you make a utility for rules, please see `../rules/utils/ast-utils.js`.
 *
 * @author Toru Nagashima <https://github.com/mysticatea>
 */
"use strict";

const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/u;
const lineBreakPattern = /\r\n|[\r\n\u2028\u2029]/u;
const shebangPattern = /^#!([^\r\n]+)/u;

/**
 * Creates a version of the `lineBreakPattern` regex with the global flag.
 * Global regexes are mutable, so this needs to be a function instead of a constant.
 * @returns {RegExp} A global regular expression that matches line terminators
 */
function createGlobalLinebreakMatcher() {
    return new RegExp(lineBreakPattern.source, "gu");
}

module.exports = {
    breakableTypePattern,
    lineBreakPattern,
    createGlobalLinebreakMatcher,
    shebangPattern
};


code:
/*
 * STOP!!! DO NOT MODIFY.
 *
 * This file is part of the ongoing work to move the eslintrc-style config
 * system into the @eslint/eslintrc package. This file needs to remain
 * unchanged in order for this work to proceed.
 *
 * If you think you need to change this file, please contact @nzakas first.
 *
 * Thanks in advance for your cooperation.
 */

/**
 * @fileoverview Validates configs.
 * @author Brandon Mills
 */

"use strict";

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

const
    util = require("util"),
    configSchema = require("../../conf/config-schema"),
    BuiltInRules = require("../rules"),
    {
        Legacy: {
            ConfigOps,
            environments: BuiltInEnvironments
        }
    } = require("@eslint/eslintrc"),
    { emitDeprecationWarning } = require("./deprecation-warnings");

const ajv = require("./ajv")();
const ruleValidators = new WeakMap();
const noop = Function.prototype;

//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
let validateSchema;
const severityMap = {
    error: 2,
    warn: 1,
    off: 0
};

/**
 * Gets a complete options schema for a rule.
 * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
 * @returns {Object} JSON Schema for the rule's options.
 */
function getRuleOptionsSchema(rule) {
    if (!rule) {
        return null;
    }

    const schema = rule.schema || rule.meta && rule.meta.schema;

    // Given a tuple of schemas, insert warning level at the beginning
    if (Array.isArray(schema)) {
        if (schema.length) {
            return {
                type: "array",
                items: schema,
                minItems: 0,
                maxItems: schema.length
            };
        }
        return {
            type: "array",
            minItems: 0,
            maxItems: 0
        };

    }

    // Given a full schema, leave it alone
    return schema || null;
}

/**
 * Validates a rule's severity and returns the severity value. Throws an error if the severity is invalid.
 * @param {options} options The given options for the rule.
 * @throws {Error} Wrong severity value.
 * @returns {number|string} The rule's severity value
 */
function validateRuleSeverity(options) {
    const severity = Array.isArray(options) ? options[0] : options;
    const normSeverity = typeof severity === "string" ? severityMap[severity.toLowerCase()] : severity;

    if (normSeverity === 0 || normSeverity === 1 || normSeverity === 2) {
        return normSeverity;
    }

    throw new Error(`\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '${util.inspect(severity).replace(/'/gu, "\"").replace(/\n/gu, "")}').\n`);

}

/**
 * Validates the non-severity options passed to a rule, based on its schema.
 * @param {{create: Function}} rule The rule to validate
 * @param {Array} localOptions The options for the rule, excluding severity
 * @throws {Error} Any rule validation errors.
 * @returns {void}
 */
function validateRuleSchema(rule, localOptions) {
    if (!ruleValidators.has(rule)) {
        const schema = getRuleOptionsSchema(rule);

        if (schema) {
            ruleValidators.set(rule, ajv.compile(schema));
        }
    }

    const validateRule = ruleValidators.get(rule);

    if (validateRule) {
        validateRule(localOptions);
        if (validateRule.errors) {
            throw new Error(validateRule.errors.map(
                error => `\tValue ${JSON.stringify(error.data)} ${error.message}.\n`
            ).join(""));
        }
    }
}

/**
 * Validates a rule's options against its schema.
 * @param {{create: Function}|null} rule The rule that the config is being validated for
 * @param {string} ruleId The rule's unique name.
 * @param {Array|number} options The given options for the rule.
 * @param {string|null} source The name of the configuration source to report in any errors. If null or undefined,
 * no source is prepended to the message.
 * @throws {Error} Upon any bad rule configuration.
 * @returns {void}
 */
function validateRuleOptions(rule, ruleId, options, source = null) {
    try {
        const severity = validateRuleSeverity(options);

        if (severity !== 0) {
            validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
        }
    } catch (err) {
        const enhancedMessage = `Configuration for rule "${ruleId}" is invalid:\n${err.message}`;

        if (typeof source === "string") {
            throw new Error(`${source}:\n\t${enhancedMessage}`);
        } else {
            throw new Error(enhancedMessage);
        }
    }
}

/**
 * Validates an environment object
 * @param {Object} environment The environment config object to validate.
 * @param {string} source The name of the configuration source to report in any errors.
 * @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded environments.
 * @returns {void}
 */
function validateEnvironment(
    environment,
    source,
    getAdditionalEnv = noop
) {

    // not having an environment is ok
    if (!environment) {
        return;
    }

    Object.keys(environment).forEach(id => {
        const env = getAdditionalEnv(id) || BuiltInEnvironments.get(id) || null;

        if (!env) {
            const message = `${source}:\n\tEnvironment key "${id}" is unknown\n`;

            throw new Error(message);
        }
    });
}

/**
 * Validates a rules config object
 * @param {Object} rulesConfig The rules config object to validate.
 * @param {string} source The name of the configuration source to report in any errors.
 * @param {(ruleId:string) => Object} getAdditionalRule A map from strings to loaded rules
 * @returns {void}
 */
function validateRules(
    rulesConfig,
    source,
    getAdditionalRule = noop
) {
    if (!rulesConfig) {
        return;
    }

    Object.keys(rulesConfig).forEach(id => {
        const rule = getAdditionalRule(id) || BuiltInRules.get(id) || null;

        validateRuleOptions(rule, id, rulesConfig[id], source);
    });
}

/**
 * Validates a `globals` section of a config file
 * @param {Object} globalsConfig The `globals` section
 * @param {string|null} source The name of the configuration source to report in the event of an error.
 * @returns {void}
 */
function validateGlobals(globalsConfig, source = null) {
    if (!globalsConfig) {
        return;
    }

    Object.entries(globalsConfig)
        .forEach(([configuredGlobal, configuredValue]) => {
            try {
                ConfigOps.normalizeConfigGlobal(configuredValue);
            } catch (err) {
                throw new Error(`ESLint configuration of global '${configuredGlobal}' in ${source} is invalid:\n${err.message}`);
            }
        });
}

/**
 * Validate `processor` configuration.
 * @param {string|undefined} processorName The processor name.
 * @param {string} source The name of config file.
 * @param {(id:string) => Processor} getProcessor The getter of defined processors.
 * @throws {Error} For invalid processor configuration.
 * @returns {void}
 */
function validateProcessor(processorName, source, getProcessor) {
    if (processorName && !getProcessor(processorName)) {
        throw new Error(`ESLint configuration of processor in '${source}' is invalid: '${processorName}' was not found.`);
    }
}

/**
 * Formats an array of schema validation errors.
 * @param {Array} errors An array of error messages to format.
 * @returns {string} Formatted error message
 */
function formatErrors(errors) {
    return errors.map(error => {
        if (error.keyword === "additionalProperties") {
            const formattedPropertyPath = error.dataPath.length ? `${error.dataPath.slice(1)}.${error.params.additionalProperty}` : error.params.additionalProperty;

            return `Unexpected top-level property "${formattedPropertyPath}"`;
        }
        if (error.keyword === "type") {
            const formattedField = error.dataPath.slice(1);
            const formattedExpectedType = Array.isArray(error.schema) ? error.schema.join("/") : error.schema;
            const formattedValue = JSON.stringify(error.data);

            return `Property "${formattedField}" is the wrong type (expected ${formattedExpectedType} but got \`${formattedValue}\`)`;
        }

        const field = error.dataPath[0] === "." ? error.dataPath.slice(1) : error.dataPath;

        return `"${field}" ${error.message}. Value: ${JSON.stringify(error.data)}`;
    }).map(message => `\t- ${message}.\n`).join("");
}

/**
 * Validates the top level properties of the config object.
 * @param {Object} config The config object to validate.
 * @param {string} source The name of the configuration source to report in any errors.
 * @throws {Error} For any config invalid per the schema.
 * @returns {void}
 */
function validateConfigSchema(config, source = null) {
    validateSchema = validateSchema || ajv.compile(configSchema);

    if (!validateSchema(config)) {
        throw new Error(`ESLint configuration in ${source} is invalid:\n${formatErrors(validateSchema.errors)}`);
    }

    if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
        emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
    }
}

/**
 * Validates an entire config object.
 * @param {Object} config The config object to validate.
 * @param {string} source The name of the configuration source to report in any errors.
 * @param {(ruleId:string) => Object} [getAdditionalRule] A map from strings to loaded rules.
 * @param {(envId:string) => Object} [getAdditionalEnv] A map from strings to loaded envs.
 * @returns {void}
 */
function validate(config, source, getAdditionalRule, getAdditionalEnv) {
    validateConfigSchema(config, source);
    validateRules(config.rules, source, getAdditionalRule);
    validateEnvironment(config.env, source, getAdditionalEnv);
    validateGlobals(config.globals, source);

    for (const override of config.overrides || []) {
        validateRules(override.rules, source, getAdditionalRule);
        validateEnvironment(override.env, source, getAdditionalEnv);
        validateGlobals(config.globals, source);
    }
}

const validated = new WeakSet();

/**
 * Validate config array object.
 * @param {ConfigArray} configArray The config array to validate.
 * @returns {void}
 */
function validateConfigArray(configArray) {
    const getPluginEnv = Map.prototype.get.bind(configArray.pluginEnvironments);
    const getPluginProcessor = Map.prototype.get.bind(configArray.pluginProcessors);
    const getPluginRule = Map.prototype.get.bind(configArray.pluginRules);

    // Validate.
    for (const element of configArray) {
        if (validated.has(element)) {
            continue;
        }
        validated.add(element);

        validateEnvironment(element.env, element.name, getPluginEnv);
        validateGlobals(element.globals, element.name);
        validateProcessor(element.processor, element.name, getPluginProcessor);
        validateRules(element.rules, element.name, getPluginRule);
    }
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = {
    getRuleOptionsSchema,
    validate,
    validateConfigArray,
    validateConfigSchema,
    validateRuleOptions
};


code:
/**
 * @fileoverview Provide the function that emits deprecation warnings.
 * @author Toru Nagashima <http://github.com/mysticatea>
 */
"use strict";

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

const path = require("path");

//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------

// Definitions for deprecation warnings.
const deprecationWarningMessages = {
    ESLINT_LEGACY_ECMAFEATURES:
        "The 'ecmaFeatures' config file property is deprecated and has no effect."
};

const sourceFileErrorCache = new Set();

/**
 * Emits a deprecation warning containing a given filepath. A new deprecation warning is emitted
 * for each unique file path, but repeated invocations with the same file path have no effect.
 * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
 * @param {string} source The name of the configuration source to report the warning for.
 * @param {string} errorCode The warning message to show.
 * @returns {void}
 */
function emitDeprecationWarning(source, errorCode) {
    const cacheKey = JSON.stringify({ source, errorCode });

    if (sourceFileErrorCache.has(cacheKey)) {
        return;
    }

    sourceFileErrorCache.add(cacheKey);

    const rel = path.relative(process.cwd(), source);
    const message = deprecationWarningMessages[errorCode];

    process.emitWarning(
        `${message} (found in "${rel}")`,
        "DeprecationWarning",
        errorCode
    );
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = {
    emitDeprecationWarning
};


code:
/**
 * @fileoverview Common utils for directives.
 *
 * This file contains only shared items for directives.
 * If you make a utility for rules, please see `../rules/utils/ast-utils.js`.
 *
 * @author gfyoung <https://github.com/gfyoung>
 */
"use strict";

const directivesPattern = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u;

module.exports = {
    directivesPattern
};


code:
/**
 * @fileoverview Handle logging for ESLint
 * @author Gyandeep Singh
 */

"use strict";

/* eslint no-console: "off" -- Logging util */

/* c8 ignore next */
module.exports = {

    /**
     * Cover for console.log
     * @param {...any} args The elements to log.
     * @returns {void}
     */
    info(...args) {
        console.log(...args);
    },

    /**
     * Cover for console.error
     * @param {...any} args The elements to log.
     * @returns {void}
     */
    error(...args) {
        console.error(...args);
    }
};


code:
/*
 * STOP!!! DO NOT MODIFY.
 *
 * This file is part of the ongoing work to move the eslintrc-style config
 * system into the @eslint/eslintrc package. This file needs to remain
 * unchanged in order for this work to proceed.
 *
 * If you think you need to change this file, please contact @nzakas first.
 *
 * Thanks in advance for your cooperation.
 */

/**
 * Utility for resolving a module relative to another module
 * @author Teddy Katz
 */

"use strict";

const { createRequire } = require("module");

module.exports = {

    /**
     * Resolves a Node module relative to another module
     * @param {string} moduleName The name of a Node module, or a path to a Node module.
     * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
     * a file rather than a directory, but the file need not actually exist.
     * @throws {Error} Any error from `module.createRequire` or its `resolve`.
     * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
     */
    resolve(moduleName, relativeToPath) {
        try {
            return createRequire(relativeToPath).resolve(moduleName);
        } catch (error) {

            // This `if` block is for older Node.js than 12.0.0. We can remove this block in the future.
            if (
                typeof error === "object" &&
                error !== null &&
                error.code === "MODULE_NOT_FOUND" &&
                !error.requireStack &&
                error.message.includes(moduleName)
            ) {
                error.message += `\nRequire stack:\n- ${relativeToPath}`;
            }
            throw error;
        }
    }
};


code:
/**
 * @fileoverview Utility to get information about the execution environment.
 * @author Kai Cataldo
 */

"use strict";

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

const path = require("path");
const spawn = require("cross-spawn");
const os = require("os");
const log = require("../shared/logging");
const packageJson = require("../../package.json");

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

/**
 * Generates and returns execution environment information.
 * @returns {string} A string that contains execution environment information.
 */
function environment() {
    const cache = new Map();

    /**
     * Checks if a path is a child of a directory.
     * @param {string} parentPath The parent path to check.
     * @param {string} childPath The path to check.
     * @returns {boolean} Whether or not the given path is a child of a directory.
     */
    function isChildOfDirectory(parentPath, childPath) {
        return !path.relative(parentPath, childPath).startsWith("..");
    }

    /**
     * Synchronously executes a shell command and formats the result.
     * @param {string} cmd The command to execute.
     * @param {Array} args The arguments to be executed with the command.
     * @throws {Error} As may be collected by `cross-spawn.sync`.
     * @returns {string} The version returned by the command.
     */
    function execCommand(cmd, args) {
        const key = [cmd, ...args].join(" ");

        if (cache.has(key)) {
            return cache.get(key);
        }

        const process = spawn.sync(cmd, args, { encoding: "utf8" });

        if (process.error) {
            throw process.error;
        }

        const result = process.stdout.trim();

        cache.set(key, result);
        return result;
    }

    /**
     * Normalizes a version number.
     * @param {string} versionStr The string to normalize.
     * @returns {string} The normalized version number.
     */
    function normalizeVersionStr(versionStr) {
        return versionStr.startsWith("v") ? versionStr : `v${versionStr}`;
    }

    /**
     * Gets bin version.
     * @param {string} bin The bin to check.
     * @throws {Error} As may be collected by `cross-spawn.sync`.
     * @returns {string} The normalized version returned by the command.
     */
    function getBinVersion(bin) {
        const binArgs = ["--version"];

        try {
            return normalizeVersionStr(execCommand(bin, binArgs));
        } catch (e) {
            log.error(`Error finding ${bin} version running the command \`${bin} ${binArgs.join(" ")}\``);
            throw e;
        }
    }

    /**
     * Gets installed npm package version.
     * @param {string} pkg The package to check.
     * @param {boolean} global Whether to check globally or not.
     * @throws {Error} As may be collected by `cross-spawn.sync`.
     * @returns {string} The normalized version returned by the command.
     */
    function getNpmPackageVersion(pkg, { global = false } = {}) {
        const npmBinArgs = ["bin", "-g"];
        const npmLsArgs = ["ls", "--depth=0", "--json", pkg];

        if (global) {
            npmLsArgs.push("-g");
        }

        try {
            const parsedStdout = JSON.parse(execCommand("npm", npmLsArgs));

            /*
             * Checking globally returns an empty JSON object, while local checks
             * include the name and version of the local project.
             */
            if (Object.keys(parsedStdout).length === 0 || !(parsedStdout.dependencies && parsedStdout.dependencies.eslint)) {
                return "Not found";
            }

            const [, processBinPath] = process.argv;
            let npmBinPath;

            try {
                npmBinPath = execCommand("npm", npmBinArgs);
            } catch (e) {
                log.error(`Error finding npm binary path when running command \`npm ${npmBinArgs.join(" ")}\``);
                throw e;
            }

            const isGlobal = isChildOfDirectory(npmBinPath, processBinPath);
            let pkgVersion = parsedStdout.dependencies.eslint.version;

            if ((global && isGlobal) || (!global && !isGlobal)) {
                pkgVersion += " (Currently used)";
            }

            return normalizeVersionStr(pkgVersion);
        } catch (e) {
            log.error(`Error finding ${pkg} version running the command \`npm ${npmLsArgs.join(" ")}\``);
            throw e;
        }
    }

    return [
        "Environment Info:",
        "",
        `Node version: ${getBinVersion("node")}`,
        `npm version: ${getBinVersion("npm")}`,
        `Local ESLint version: ${getNpmPackageVersion("eslint", { global: false })}`,
        `Global ESLint version: ${getNpmPackageVersion("eslint", { global: true })}`,
        `Operating System: ${os.platform()} ${os.release()}`
    ].join("\n");
}

/**
 * Returns version of currently executing ESLint.
 * @returns {string} The version from the currently executing ESLint's package.json.
 */
function version() {
    return `v${packageJson.version}`;
}

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

module.exports = {
    environment,
    version
};


code:
/**
 * @fileoverview Helpers for severity values (e.g. normalizing different types).
 * @author Bryan Mishkin
 */

"use strict";

/**
 * Convert severity value of different types to a string.
 * @param {string|number} severity severity value
 * @throws error if severity is invalid
 * @returns {string} severity string
 */
function normalizeSeverityToString(severity) {
    if ([2, "2", "error"].includes(severity)) {
        return "error";
    }
    if ([1, "1", "warn"].includes(severity)) {
        return "warn";
    }
    if ([0, "0", "off"].includes(severity)) {
        return "off";
    }
    throw new Error(`Invalid severity value: ${severity}`);
}

/**
 * Convert severity value of different types to a number.
 * @param {string|number} severity severity value
 * @throws error if severity is invalid
 * @returns {number} severity number
 */
function normalizeSeverityToNumber(severity) {
    if ([2, "2", "error"].includes(severity)) {
        return 2;
    }
    if ([1, "1", "warn"].includes(severity)) {
        return 1;
    }
    if ([0, "0", "off"].includes(severity)) {
        return 0;
    }
    throw new Error(`Invalid severity value: ${severity}`);
}

module.exports = {
    normalizeSeverityToString,
    normalizeSeverityToNumber
};


code:
/**
 * @fileoverview Utilities to operate on strings.
 * @author Stephen Wade
 */

"use strict";

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

const Graphemer = require("graphemer").default;

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

// eslint-disable-next-line no-control-regex -- intentionally including control characters
const ASCII_REGEX = /^[\u0000-\u007f]*$/u;

/** @type {Graphemer | undefined} */
let splitter;

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

/**
 * Converts the first letter of a string to uppercase.
 * @param {string} string The string to operate on
 * @returns {string} The converted string
 */
function upperCaseFirst(string) {
    if (string.length <= 1) {
        return string.toUpperCase();
    }
    return string[0].toUpperCase() + string.slice(1);
}

/**
 * Counts graphemes in a given string.
 * @param {string} value A string to count graphemes.
 * @returns {number} The number of graphemes in `value`.
 */
function getGraphemeCount(value) {
    if (ASCII_REGEX.test(value)) {
        return value.length;
    }

    if (!splitter) {
        splitter = new Graphemer();
    }

    return splitter.countGraphemes(value);
}

module.exports = {
    upperCaseFirst,
    getGraphemeCount
};