| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /**
- * @fileoverview Rule to enforce consistent naming of "this" context variables
- * @author Raphael Pigulla
- */
- "use strict";
- //------------------------------------------------------------------------------
- // Rule Definition
- //------------------------------------------------------------------------------
- /** @type {import('../types').Rule.RuleModule} */
- module.exports = {
- meta: {
- type: "suggestion",
- docs: {
- description:
- "Enforce consistent naming when capturing the current execution context",
- recommended: false,
- frozen: true,
- url: "https://eslint.org/docs/latest/rules/consistent-this",
- },
- schema: {
- type: "array",
- items: {
- type: "string",
- minLength: 1,
- },
- uniqueItems: true,
- },
- defaultOptions: ["that"],
- messages: {
- aliasNotAssignedToThis:
- "Designated alias '{{name}}' is not assigned to 'this'.",
- unexpectedAlias: "Unexpected alias '{{name}}' for 'this'.",
- },
- },
- create(context) {
- const aliases = context.options;
- const sourceCode = context.sourceCode;
- /**
- * 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.
- * @param {ASTNode} node The node that represents the scope to check.
- * @returns {void}
- */
- function ensureWasAssigned(node) {
- const scope = sourceCode.getScope(node);
- // if this is program scope we also need to check module scope
- const extraScope =
- node.type === "Program" && node.sourceType === "module"
- ? scope.childScopes[0]
- : null;
- aliases.forEach(alias => {
- checkWasAssigned(alias, scope);
- if (extraScope) {
- checkWasAssigned(alias, extraScope);
- }
- });
- }
- 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);
- }
- },
- };
- },
- };
|