|                                                                                                                                                                                |  | /** * @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible. * @author Josh Perez */"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");const keywords = require("./utils/keywords");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
// `null` literal must be handled separately.
const literalTypesToCheck = new Set(["string", "boolean"]);
/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",
        docs: {            description: "Enforce dot notation whenever possible",            recommended: false,            url: "https://eslint.org/docs/latest/rules/dot-notation"        },
        schema: [            {                type: "object",                properties: {                    allowKeywords: {                        type: "boolean",                        default: true                    },                    allowPattern: {                        type: "string",                        default: ""                    }                },                additionalProperties: false            }        ],
        fixable: "code",
        messages: {            useDot: "[{{key}}] is better written in dot notation.",            useBrackets: ".{{key}} is a syntax error."        }    },
    create(context) {        const options = context.options[0] || {};        const allowKeywords = options.allowKeywords === void 0 || options.allowKeywords;        const sourceCode = context.sourceCode;
        let allowPattern;
        if (options.allowPattern) {            allowPattern = new RegExp(options.allowPattern, "u");        }
        /**         * Check if the property is valid dot notation         * @param {ASTNode} node The dot notation node         * @param {string} value Value which is to be checked         * @returns {void}         */        function checkComputedProperty(node, value) {            if (                validIdentifier.test(value) &&                (allowKeywords || !keywords.includes(String(value))) &&                !(allowPattern && allowPattern.test(value))            ) {                const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
                context.report({                    node: node.property,                    messageId: "useDot",                    data: {                        key: formattedValue                    },                    *fix(fixer) {                        const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);                        const rightBracket = sourceCode.getLastToken(node);                        const nextToken = sourceCode.getTokenAfter(node);
                        // Don't perform any fixes if there are comments inside the brackets.
                        if (sourceCode.commentsExistBetween(leftBracket, rightBracket)) {                            return;                        }
                        // Replace the brackets by an identifier.
                        if (!node.optional) {                            yield fixer.insertTextBefore(                                leftBracket,                                astUtils.isDecimalInteger(node.object) ? " ." : "."                            );                        }                        yield fixer.replaceTextRange(                            [leftBracket.range[0], rightBracket.range[1]],                            value                        );
                        // Insert a space after the property if it will be connected to the next token.
                        if (                            nextToken &&                            rightBracket.range[1] === nextToken.range[0] &&                            !astUtils.canTokensBeAdjacent(String(value), nextToken)                        ) {                            yield fixer.insertTextAfter(node, " ");                        }                    }                });            }        }
        return {            MemberExpression(node) {                if (                    node.computed &&                    node.property.type === "Literal" &&                    (literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property))                ) {                    checkComputedProperty(node, node.property.value);                }                if (                    node.computed &&                    astUtils.isStaticTemplateLiteral(node.property)                ) {                    checkComputedProperty(node, node.property.quasis[0].value.cooked);                }                if (                    !allowKeywords &&                    !node.computed &&                    node.property.type === "Identifier" &&                    keywords.includes(String(node.property.name))                ) {                    context.report({                        node: node.property,                        messageId: "useBrackets",                        data: {                            key: node.property.name                        },                        *fix(fixer) {                            const dotToken = sourceCode.getTokenBefore(node.property);
                            // A statement that starts with `let[` is parsed as a destructuring variable declaration, not a MemberExpression.
                            if (node.object.type === "Identifier" && node.object.name === "let" && !node.optional) {                                return;                            }
                            // Don't perform any fixes if there are comments between the dot and the property name.
                            if (sourceCode.commentsExistBetween(dotToken, node.property)) {                                return;                            }
                            // Replace the identifier to brackets.
                            if (!node.optional) {                                yield fixer.remove(dotToken);                            }                            yield fixer.replaceText(node.property, `["${node.property.name}"]`);                        }                    });                }            }        };    }};
 |