source: imaps-frontend/node_modules/eslint/lib/rules/no-param-reassign.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/**
2 * @fileoverview Disallow reassignment of function parameters.
3 * @author Nat Burns
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/u;
12
13/** @type {import('../shared/types').Rule} */
14module.exports = {
15 meta: {
16 type: "suggestion",
17
18 docs: {
19 description: "Disallow reassigning `function` parameters",
20 recommended: false,
21 url: "https://eslint.org/docs/latest/rules/no-param-reassign"
22 },
23
24 schema: [
25 {
26 oneOf: [
27 {
28 type: "object",
29 properties: {
30 props: {
31 enum: [false]
32 }
33 },
34 additionalProperties: false
35 },
36 {
37 type: "object",
38 properties: {
39 props: {
40 enum: [true]
41 },
42 ignorePropertyModificationsFor: {
43 type: "array",
44 items: {
45 type: "string"
46 },
47 uniqueItems: true
48 },
49 ignorePropertyModificationsForRegex: {
50 type: "array",
51 items: {
52 type: "string"
53 },
54 uniqueItems: true
55 }
56 },
57 additionalProperties: false
58 }
59 ]
60 }
61 ],
62
63 messages: {
64 assignmentToFunctionParam: "Assignment to function parameter '{{name}}'.",
65 assignmentToFunctionParamProp: "Assignment to property of function parameter '{{name}}'."
66 }
67 },
68
69 create(context) {
70 const props = context.options[0] && context.options[0].props;
71 const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
72 const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];
73 const sourceCode = context.sourceCode;
74
75 /**
76 * Checks whether or not the reference modifies properties of its variable.
77 * @param {Reference} reference A reference to check.
78 * @returns {boolean} Whether or not the reference modifies properties of its variable.
79 */
80 function isModifyingProp(reference) {
81 let node = reference.identifier;
82 let parent = node.parent;
83
84 while (parent && (!stopNodePattern.test(parent.type) ||
85 parent.type === "ForInStatement" || parent.type === "ForOfStatement")) {
86 switch (parent.type) {
87
88 // e.g. foo.a = 0;
89 case "AssignmentExpression":
90 return parent.left === node;
91
92 // e.g. ++foo.a;
93 case "UpdateExpression":
94 return true;
95
96 // e.g. delete foo.a;
97 case "UnaryExpression":
98 if (parent.operator === "delete") {
99 return true;
100 }
101 break;
102
103 // e.g. for (foo.a in b) {}
104 case "ForInStatement":
105 case "ForOfStatement":
106 if (parent.left === node) {
107 return true;
108 }
109
110 // this is a stop node for parent.right and parent.body
111 return false;
112
113 // EXCLUDES: e.g. cache.get(foo.a).b = 0;
114 case "CallExpression":
115 if (parent.callee !== node) {
116 return false;
117 }
118 break;
119
120 // EXCLUDES: e.g. cache[foo.a] = 0;
121 case "MemberExpression":
122 if (parent.property === node) {
123 return false;
124 }
125 break;
126
127 // EXCLUDES: e.g. ({ [foo]: a }) = bar;
128 case "Property":
129 if (parent.key === node) {
130 return false;
131 }
132
133 break;
134
135 // EXCLUDES: e.g. (foo ? a : b).c = bar;
136 case "ConditionalExpression":
137 if (parent.test === node) {
138 return false;
139 }
140
141 break;
142
143 // no default
144 }
145
146 node = parent;
147 parent = node.parent;
148 }
149
150 return false;
151 }
152
153 /**
154 * Tests that an identifier name matches any of the ignored property assignments.
155 * First we test strings in ignoredPropertyAssignmentsFor.
156 * Then we instantiate and test RegExp objects from ignoredPropertyAssignmentsForRegex strings.
157 * @param {string} identifierName A string that describes the name of an identifier to
158 * ignore property assignments for.
159 * @returns {boolean} Whether the string matches an ignored property assignment regular expression or not.
160 */
161 function isIgnoredPropertyAssignment(identifierName) {
162 return ignoredPropertyAssignmentsFor.includes(identifierName) ||
163 ignoredPropertyAssignmentsForRegex.some(ignored => new RegExp(ignored, "u").test(identifierName));
164 }
165
166 /**
167 * Reports a reference if is non initializer and writable.
168 * @param {Reference} reference A reference to check.
169 * @param {int} index The index of the reference in the references.
170 * @param {Reference[]} references The array that the reference belongs to.
171 * @returns {void}
172 */
173 function checkReference(reference, index, references) {
174 const identifier = reference.identifier;
175
176 if (identifier &&
177 !reference.init &&
178
179 /*
180 * Destructuring assignments can have multiple default value,
181 * so possibly there are multiple writeable references for the same identifier.
182 */
183 (index === 0 || references[index - 1].identifier !== identifier)
184 ) {
185 if (reference.isWrite()) {
186 context.report({
187 node: identifier,
188 messageId: "assignmentToFunctionParam",
189 data: { name: identifier.name }
190 });
191 } else if (props && isModifyingProp(reference) && !isIgnoredPropertyAssignment(identifier.name)) {
192 context.report({
193 node: identifier,
194 messageId: "assignmentToFunctionParamProp",
195 data: { name: identifier.name }
196 });
197 }
198 }
199 }
200
201 /**
202 * Finds and reports references that are non initializer and writable.
203 * @param {Variable} variable A variable to check.
204 * @returns {void}
205 */
206 function checkVariable(variable) {
207 if (variable.defs[0].type === "Parameter") {
208 variable.references.forEach(checkReference);
209 }
210 }
211
212 /**
213 * Checks parameters of a given function node.
214 * @param {ASTNode} node A function node to check.
215 * @returns {void}
216 */
217 function checkForFunction(node) {
218 sourceCode.getDeclaredVariables(node).forEach(checkVariable);
219 }
220
221 return {
222
223 // `:exit` is needed for the `node.parent` property of identifier nodes.
224 "FunctionDeclaration:exit": checkForFunction,
225 "FunctionExpression:exit": checkForFunction,
226 "ArrowFunctionExpression:exit": checkForFunction
227 };
228
229 }
230};
Note: See TracBrowser for help on using the repository browser.