|                                                                                                                                                                                 |  | /** * @fileoverview Rule that warns when identifier names are shorter or longer * than the values provided in configuration. * @author Burak Yigit Kaya aka BYK */
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const { getGraphemeCount } = require("../shared/string-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",
        docs: {            description: "Enforce minimum and maximum identifier lengths",            recommended: false,            url: "https://eslint.org/docs/latest/rules/id-length"        },
        schema: [            {                type: "object",                properties: {                    min: {                        type: "integer",                        default: 2                    },                    max: {                        type: "integer"                    },                    exceptions: {                        type: "array",                        uniqueItems: true,                        items: {                            type: "string"                        }                    },                    exceptionPatterns: {                        type: "array",                        uniqueItems: true,                        items: {                            type: "string"                        }                    },                    properties: {                        enum: ["always", "never"]                    }                },                additionalProperties: false            }        ],        messages: {            tooShort: "Identifier name '{{name}}' is too short (< {{min}}).",            tooShortPrivate: "Identifier name '#{{name}}' is too short (< {{min}}).",            tooLong: "Identifier name '{{name}}' is too long (> {{max}}).",            tooLongPrivate: "Identifier name #'{{name}}' is too long (> {{max}})."        }    },
    create(context) {        const options = context.options[0] || {};        const minLength = typeof options.min !== "undefined" ? options.min : 2;        const maxLength = typeof options.max !== "undefined" ? options.max : Infinity;        const properties = options.properties !== "never";        const exceptions = new Set(options.exceptions);        const exceptionPatterns = (options.exceptionPatterns || []).map(pattern => new RegExp(pattern, "u"));        const reportedNodes = new Set();
        /**         * Checks if a string matches the provided exception patterns         * @param {string} name The string to check.         * @returns {boolean} if the string is a match         * @private         */        function matchesExceptionPattern(name) {            return exceptionPatterns.some(pattern => pattern.test(name));        }
        const SUPPORTED_EXPRESSIONS = {            MemberExpression: properties && function(parent) {                return !parent.computed && (
                    // regular property assignment
                    (parent.parent.left === parent && parent.parent.type === "AssignmentExpression" ||
                    // or the last identifier in an ObjectPattern destructuring
                    parent.parent.type === "Property" && parent.parent.value === parent &&                    parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent)                );            },            AssignmentPattern(parent, node) {                return parent.left === node;            },            VariableDeclarator(parent, node) {                return parent.id === node;            },            Property(parent, node) {
                if (parent.parent.type === "ObjectPattern") {                    const isKeyAndValueSame = parent.value.name === parent.key.name;
                    return (                        !isKeyAndValueSame && parent.value === node ||                        isKeyAndValueSame && parent.key === node && properties                    );                }                return properties && !parent.computed && parent.key.name === node.name;            },            ImportDefaultSpecifier: true,            RestElement: true,            FunctionExpression: true,            ArrowFunctionExpression: true,            ClassDeclaration: true,            FunctionDeclaration: true,            MethodDefinition: true,            PropertyDefinition: true,            CatchClause: true,            ArrayPattern: true        };
        return {            [[                "Identifier",                "PrivateIdentifier"            ]](node) {                const name = node.name;                const parent = node.parent;
                const nameLength = getGraphemeCount(name);
                const isShort = nameLength < minLength;                const isLong = nameLength > maxLength;
                if (!(isShort || isLong) || exceptions.has(name) || matchesExceptionPattern(name)) {                    return; // Nothing to report
                }
                const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];
                /*                 * We used the range instead of the node because it's possible                 * for the same identifier to be represented by two different                 * nodes, with the most clear example being shorthand properties:                 * { foo }                 * In this case, "foo" is represented by one node for the name                 * and one for the value. The only way to know they are the same                 * is to look at the range.                 */                if (isValidExpression && !reportedNodes.has(node.range.toString()) && (isValidExpression === true || isValidExpression(parent, node))) {                    reportedNodes.add(node.range.toString());
                    let messageId = isShort ? "tooShort" : "tooLong";
                    if (node.type === "PrivateIdentifier") {                        messageId += "Private";                    }
                    context.report({                        node,                        messageId,                        data: { name, min: minLength, max: maxLength }                    });                }            }        };    }};
 |