| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 | /** * @fileoverview Rule to enforce consistent naming of "this" context variables * @author Raphael Pigulla */"use strict";//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------/** @type {import('../shared/types').Rule} */module.exports = {    meta: {        type: "suggestion",        docs: {            description: "Enforce consistent naming when capturing the current execution context",            recommended: false,            url: "https://eslint.org/docs/rules/consistent-this"        },        schema: {            type: "array",            items: {                type: "string",                minLength: 1            },            uniqueItems: true        },        messages: {            aliasNotAssignedToThis: "Designated alias '{{name}}' is not assigned to 'this'.",            unexpectedAlias: "Unexpected alias '{{name}}' for 'this'."        }    },    create(context) {        let aliases = [];        if (context.options.length === 0) {            aliases.push("that");        } else {            aliases = context.options;        }        /**         * Reports that a variable declarator or assignment expression is assigning         * a non-'this' value to the specified alias.         * @param {ASTNode} node The assigning node.         * @param {string} name the name of the alias that was incorrectly used.         * @returns {void}         */        function reportBadAssignment(node, name) {            context.report({ node, messageId: "aliasNotAssignedToThis", data: { name } });        }        /**         * Checks that an assignment to an identifier only assigns 'this' to the         * appropriate alias, and the alias is only assigned to 'this'.         * @param {ASTNode} node The assigning node.         * @param {Identifier} name The name of the variable assigned to.         * @param {Expression} value The value of the assignment.         * @returns {void}         */        function checkAssignment(node, name, value) {            const isThis = value.type === "ThisExpression";            if (aliases.includes(name)) {                if (!isThis || node.operator && node.operator !== "=") {                    reportBadAssignment(node, name);                }            } else if (isThis) {                context.report({ node, messageId: "unexpectedAlias", data: { name } });            }        }        /**         * Ensures that a variable declaration of the alias in a program or function         * is assigned to the correct value.         * @param {string} alias alias the check the assignment of.         * @param {Object} scope scope of the current code we are checking.         * @private         * @returns {void}         */        function checkWasAssigned(alias, scope) {            const variable = scope.set.get(alias);            if (!variable) {                return;            }            if (variable.defs.some(def => def.node.type === "VariableDeclarator" &&                def.node.init !== null)) {                return;            }            /*             * The alias has been declared and not assigned: check it was             * assigned later in the same scope.             */            if (!variable.references.some(reference => {                const write = reference.writeExpr;                return (                    reference.from === scope &&                    write && write.type === "ThisExpression" &&                    write.parent.operator === "="                );            })) {                variable.defs.map(def => def.node).forEach(node => {                    reportBadAssignment(node, alias);                });            }        }        /**         * Check each alias to ensure that is was assigned to the correct value.         * @returns {void}         */        function ensureWasAssigned() {            const scope = context.getScope();            aliases.forEach(alias => {                checkWasAssigned(alias, scope);            });        }        return {            "Program:exit": ensureWasAssigned,            "FunctionExpression:exit": ensureWasAssigned,            "FunctionDeclaration:exit": ensureWasAssigned,            VariableDeclarator(node) {                const id = node.id;                const isDestructuring =                    id.type === "ArrayPattern" || id.type === "ObjectPattern";                if (node.init !== null && !isDestructuring) {                    checkAssignment(node, id.name, node.init);                }            },            AssignmentExpression(node) {                if (node.left.type === "Identifier") {                    checkAssignment(node, node.left.name, node.right);                }            }        };    }};
 |