123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /**
- * @fileoverview Rule to disallow assignments where both sides are exactly the same
- * @author Toru Nagashima
- */
-
- "use strict";
-
- //------------------------------------------------------------------------------
- // Requirements
- //------------------------------------------------------------------------------
-
- const astUtils = require("../util/ast-utils");
-
- //------------------------------------------------------------------------------
- // Helpers
- //------------------------------------------------------------------------------
-
- const SPACES = /\s+/g;
-
- /**
- * Checks whether the property of 2 given member expression nodes are the same
- * property or not.
- *
- * @param {ASTNode} left - A member expression node to check.
- * @param {ASTNode} right - Another member expression node to check.
- * @returns {boolean} `true` if the member expressions have the same property.
- */
- function isSameProperty(left, right) {
- if (left.property.type === "Identifier" &&
- left.property.type === right.property.type &&
- left.property.name === right.property.name &&
- left.computed === right.computed
- ) {
- return true;
- }
-
- const lname = astUtils.getStaticPropertyName(left);
- const rname = astUtils.getStaticPropertyName(right);
-
- return lname !== null && lname === rname;
- }
-
- /**
- * Checks whether 2 given member expression nodes are the reference to the same
- * property or not.
- *
- * @param {ASTNode} left - A member expression node to check.
- * @param {ASTNode} right - Another member expression node to check.
- * @returns {boolean} `true` if the member expressions are the reference to the
- * same property or not.
- */
- function isSameMember(left, right) {
- if (!isSameProperty(left, right)) {
- return false;
- }
-
- const lobj = left.object;
- const robj = right.object;
-
- if (lobj.type !== robj.type) {
- return false;
- }
- if (lobj.type === "MemberExpression") {
- return isSameMember(lobj, robj);
- }
- return lobj.type === "Identifier" && lobj.name === robj.name;
- }
-
- /**
- * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
- *
- * @param {ASTNode|null} left - A left node to traverse. This is a Pattern or
- * a Property.
- * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or
- * a Property.
- * @param {boolean} props - The flag to check member expressions as well.
- * @param {Function} report - A callback function to report.
- * @returns {void}
- */
- function eachSelfAssignment(left, right, props, report) {
- if (!left || !right) {
-
- // do nothing
- } else if (
- left.type === "Identifier" &&
- right.type === "Identifier" &&
- left.name === right.name
- ) {
- report(right);
- } else if (
- left.type === "ArrayPattern" &&
- right.type === "ArrayExpression"
- ) {
- const end = Math.min(left.elements.length, right.elements.length);
-
- for (let i = 0; i < end; ++i) {
- const rightElement = right.elements[i];
-
- eachSelfAssignment(left.elements[i], rightElement, props, report);
-
- // After a spread element, those indices are unknown.
- if (rightElement && rightElement.type === "SpreadElement") {
- break;
- }
- }
- } else if (
- left.type === "RestElement" &&
- right.type === "SpreadElement"
- ) {
- eachSelfAssignment(left.argument, right.argument, props, report);
- } else if (
- left.type === "ObjectPattern" &&
- right.type === "ObjectExpression" &&
- right.properties.length >= 1
- ) {
-
- /*
- * Gets the index of the last spread property.
- * It's possible to overwrite properties followed by it.
- */
- let startJ = 0;
-
- for (let i = right.properties.length - 1; i >= 0; --i) {
- const propType = right.properties[i].type;
-
- if (propType === "SpreadElement" || propType === "ExperimentalSpreadProperty") {
- startJ = i + 1;
- break;
- }
- }
-
- for (let i = 0; i < left.properties.length; ++i) {
- for (let j = startJ; j < right.properties.length; ++j) {
- eachSelfAssignment(
- left.properties[i],
- right.properties[j],
- props,
- report
- );
- }
- }
- } else if (
- left.type === "Property" &&
- right.type === "Property" &&
- !left.computed &&
- !right.computed &&
- right.kind === "init" &&
- !right.method &&
- left.key.name === right.key.name
- ) {
- eachSelfAssignment(left.value, right.value, props, report);
- } else if (
- props &&
- left.type === "MemberExpression" &&
- right.type === "MemberExpression" &&
- isSameMember(left, right)
- ) {
- report(right);
- }
- }
-
- //------------------------------------------------------------------------------
- // Rule Definition
- //------------------------------------------------------------------------------
-
- module.exports = {
- meta: {
- type: "problem",
-
- docs: {
- description: "disallow assignments where both sides are exactly the same",
- category: "Best Practices",
- recommended: true,
- url: "https://eslint.org/docs/rules/no-self-assign"
- },
-
- schema: [
- {
- type: "object",
- properties: {
- props: {
- type: "boolean"
- }
- },
- additionalProperties: false
- }
- ]
- },
-
- create(context) {
- const sourceCode = context.getSourceCode();
- const [{ props = true } = {}] = context.options;
-
- /**
- * Reports a given node as self assignments.
- *
- * @param {ASTNode} node - A node to report. This is an Identifier node.
- * @returns {void}
- */
- function report(node) {
- context.report({
- node,
- message: "'{{name}}' is assigned to itself.",
- data: {
- name: sourceCode.getText(node).replace(SPACES, "")
- }
- });
- }
-
- return {
- AssignmentExpression(node) {
- if (node.operator === "=") {
- eachSelfAssignment(node.left, node.right, props, report);
- }
- }
- };
- }
- };
|