.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-self-assign.js
1 /**
2  * @fileoverview Rule to disallow assignments where both sides are exactly the same
3  * @author Toru Nagashima
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Helpers
16 //------------------------------------------------------------------------------
17
18 const SPACES = /\s+/gu;
19
20 /**
21  * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
22  * @param {ASTNode|null} left A left node to traverse. This is a Pattern or
23  *      a Property.
24  * @param {ASTNode|null} right A right node to traverse. This is a Pattern or
25  *      a Property.
26  * @param {boolean} props The flag to check member expressions as well.
27  * @param {Function} report A callback function to report.
28  * @returns {void}
29  */
30 function eachSelfAssignment(left, right, props, report) {
31     if (!left || !right) {
32
33         // do nothing
34     } else if (
35         left.type === "Identifier" &&
36         right.type === "Identifier" &&
37         left.name === right.name
38     ) {
39         report(right);
40     } else if (
41         left.type === "ArrayPattern" &&
42         right.type === "ArrayExpression"
43     ) {
44         const end = Math.min(left.elements.length, right.elements.length);
45
46         for (let i = 0; i < end; ++i) {
47             const leftElement = left.elements[i];
48             const rightElement = right.elements[i];
49
50             // Avoid cases such as [...a] = [...a, 1]
51             if (
52                 leftElement &&
53                 leftElement.type === "RestElement" &&
54                 i < right.elements.length - 1
55             ) {
56                 break;
57             }
58
59             eachSelfAssignment(leftElement, rightElement, props, report);
60
61             // After a spread element, those indices are unknown.
62             if (rightElement && rightElement.type === "SpreadElement") {
63                 break;
64             }
65         }
66     } else if (
67         left.type === "RestElement" &&
68         right.type === "SpreadElement"
69     ) {
70         eachSelfAssignment(left.argument, right.argument, props, report);
71     } else if (
72         left.type === "ObjectPattern" &&
73         right.type === "ObjectExpression" &&
74         right.properties.length >= 1
75     ) {
76
77         /*
78          * Gets the index of the last spread property.
79          * It's possible to overwrite properties followed by it.
80          */
81         let startJ = 0;
82
83         for (let i = right.properties.length - 1; i >= 0; --i) {
84             const propType = right.properties[i].type;
85
86             if (propType === "SpreadElement" || propType === "ExperimentalSpreadProperty") {
87                 startJ = i + 1;
88                 break;
89             }
90         }
91
92         for (let i = 0; i < left.properties.length; ++i) {
93             for (let j = startJ; j < right.properties.length; ++j) {
94                 eachSelfAssignment(
95                     left.properties[i],
96                     right.properties[j],
97                     props,
98                     report
99                 );
100             }
101         }
102     } else if (
103         left.type === "Property" &&
104         right.type === "Property" &&
105         right.kind === "init" &&
106         !right.method
107     ) {
108         const leftName = astUtils.getStaticPropertyName(left);
109
110         if (leftName !== null && leftName === astUtils.getStaticPropertyName(right)) {
111             eachSelfAssignment(left.value, right.value, props, report);
112         }
113     } else if (
114         props &&
115         astUtils.skipChainExpression(left).type === "MemberExpression" &&
116         astUtils.skipChainExpression(right).type === "MemberExpression" &&
117         astUtils.isSameReference(left, right)
118     ) {
119         report(right);
120     }
121 }
122
123 //------------------------------------------------------------------------------
124 // Rule Definition
125 //------------------------------------------------------------------------------
126
127 module.exports = {
128     meta: {
129         type: "problem",
130
131         docs: {
132             description: "disallow assignments where both sides are exactly the same",
133             category: "Best Practices",
134             recommended: true,
135             url: "https://eslint.org/docs/rules/no-self-assign"
136         },
137
138         schema: [
139             {
140                 type: "object",
141                 properties: {
142                     props: {
143                         type: "boolean",
144                         default: true
145                     }
146                 },
147                 additionalProperties: false
148             }
149         ],
150
151         messages: {
152             selfAssignment: "'{{name}}' is assigned to itself."
153         }
154     },
155
156     create(context) {
157         const sourceCode = context.getSourceCode();
158         const [{ props = true } = {}] = context.options;
159
160         /**
161          * Reports a given node as self assignments.
162          * @param {ASTNode} node A node to report. This is an Identifier node.
163          * @returns {void}
164          */
165         function report(node) {
166             context.report({
167                 node,
168                 messageId: "selfAssignment",
169                 data: {
170                     name: sourceCode.getText(node).replace(SPACES, "")
171                 }
172             });
173         }
174
175         return {
176             AssignmentExpression(node) {
177                 if (node.operator === "=") {
178                     eachSelfAssignment(node.left, node.right, props, report);
179                 }
180             }
181         };
182     }
183 };