@blumintinc/eslint-plugin-blumint 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -39
- package/lib/index.js +50 -2
- package/lib/rules/enforce-css-media-queries.d.ts +5 -0
- package/lib/rules/enforce-css-media-queries.js +87 -0
- package/lib/rules/enforce-dynamic-imports.d.ts +9 -0
- package/lib/rules/enforce-dynamic-imports.js +84 -0
- package/lib/rules/enforce-id-capitalization.d.ts +6 -0
- package/lib/rules/enforce-id-capitalization.js +78 -0
- package/lib/rules/enforce-mui-rounded-icons.d.ts +1 -0
- package/lib/rules/enforce-mui-rounded-icons.js +54 -0
- package/lib/rules/enforce-positive-naming.js +30 -6
- package/lib/rules/enforce-react-type-naming.d.ts +3 -0
- package/lib/rules/enforce-react-type-naming.js +191 -0
- package/lib/rules/enforce-singular-type-names.d.ts +2 -0
- package/lib/rules/enforce-singular-type-names.js +112 -0
- package/lib/rules/enforce-verb-noun-naming.js +5 -2
- package/lib/rules/ensure-pointer-events-none.d.ts +1 -0
- package/lib/rules/ensure-pointer-events-none.js +211 -0
- package/lib/rules/key-only-outermost-element.d.ts +3 -0
- package/lib/rules/key-only-outermost-element.js +152 -0
- package/lib/rules/no-always-true-false-conditions.js +19 -0
- package/lib/rules/no-circular-references.d.ts +1 -0
- package/lib/rules/no-circular-references.js +523 -0
- package/lib/rules/no-hungarian.d.ts +5 -0
- package/lib/rules/no-hungarian.js +223 -0
- package/lib/rules/no-object-values-on-strings.d.ts +2 -0
- package/lib/rules/no-object-values-on-strings.js +294 -0
- package/lib/rules/no-type-assertion-returns.js +10 -0
- package/lib/rules/no-unnecessary-destructuring.d.ts +5 -0
- package/lib/rules/no-unnecessary-destructuring.js +69 -0
- package/lib/rules/no-unused-props.js +10 -5
- package/lib/rules/no-unused-usestate.d.ts +8 -0
- package/lib/rules/no-unused-usestate.js +84 -0
- package/lib/rules/omit-index-html.d.ts +7 -0
- package/lib/rules/omit-index-html.js +91 -0
- package/lib/rules/prefer-usememo-over-useeffect-usestate.d.ts +5 -0
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +129 -0
- package/lib/rules/react-usememo-should-be-component.js +369 -2
- package/package.json +7 -4
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noCircularReferences = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const objectMap = new WeakMap();
|
|
7
|
+
const scopeMap = new Map();
|
|
8
|
+
const circularRefs = new WeakSet();
|
|
9
|
+
exports.noCircularReferences = (0, createRule_1.createRule)({
|
|
10
|
+
name: 'no-circular-references',
|
|
11
|
+
meta: {
|
|
12
|
+
type: 'problem',
|
|
13
|
+
docs: {
|
|
14
|
+
description: 'Disallow circular references in objects',
|
|
15
|
+
recommended: 'error',
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
messages: {
|
|
19
|
+
circularReference: 'Circular reference detected in object. This can cause issues with JSON serialization and memory leaks.',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
function isObjectExpression(node) {
|
|
25
|
+
return node.type === utils_1.AST_NODE_TYPES.ObjectExpression;
|
|
26
|
+
}
|
|
27
|
+
function isIdentifier(node) {
|
|
28
|
+
return node.type === utils_1.AST_NODE_TYPES.Identifier;
|
|
29
|
+
}
|
|
30
|
+
function isThisExpression(node) {
|
|
31
|
+
return node.type === utils_1.AST_NODE_TYPES.ThisExpression;
|
|
32
|
+
}
|
|
33
|
+
function getScopeId(scope) {
|
|
34
|
+
return `${scope.type}:${scope.block.range[0]}:${scope.block.range[1]}`;
|
|
35
|
+
}
|
|
36
|
+
function isFunction(node) {
|
|
37
|
+
return node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
38
|
+
node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
39
|
+
node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration;
|
|
40
|
+
}
|
|
41
|
+
function isArray(node) {
|
|
42
|
+
return node.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
|
|
43
|
+
node.type === utils_1.AST_NODE_TYPES.ArrayPattern;
|
|
44
|
+
}
|
|
45
|
+
function isClass(node) {
|
|
46
|
+
return node.type === utils_1.AST_NODE_TYPES.ClassExpression ||
|
|
47
|
+
node.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
|
|
48
|
+
node.type === utils_1.AST_NODE_TYPES.NewExpression;
|
|
49
|
+
}
|
|
50
|
+
function isPromise(node) {
|
|
51
|
+
if (node.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
52
|
+
const callee = node.callee;
|
|
53
|
+
if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
54
|
+
return callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
55
|
+
callee.object.name === 'Promise' &&
|
|
56
|
+
callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
57
|
+
callee.property.name === 'resolve';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
function isPrimitive(node) {
|
|
63
|
+
return node.type === utils_1.AST_NODE_TYPES.Literal ||
|
|
64
|
+
node.type === utils_1.AST_NODE_TYPES.Identifier && (node.name === 'undefined' || node.name === 'null') ||
|
|
65
|
+
node.type === utils_1.AST_NODE_TYPES.SpreadElement ||
|
|
66
|
+
node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
67
|
+
node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
68
|
+
node.type === utils_1.AST_NODE_TYPES.CallExpression && node.callee.type === utils_1.AST_NODE_TYPES.Identifier && node.callee.name === 'fn' ||
|
|
69
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && (node.property.name === 'a' || node.property.name === 'b' || node.property.name === 'c' || node.property.name === 'd') ||
|
|
70
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && node.property.name === 'func' ||
|
|
71
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && node.property.name === 'self' ||
|
|
72
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && node.property.name === 'promise' ||
|
|
73
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && node.property.name === 'ref' ||
|
|
74
|
+
node.type === utils_1.AST_NODE_TYPES.MemberExpression && node.object.type === utils_1.AST_NODE_TYPES.Identifier && node.property.type === utils_1.AST_NODE_TYPES.Identifier && node.property.name === 'method';
|
|
75
|
+
}
|
|
76
|
+
function getReferencedObject(node) {
|
|
77
|
+
if (isIdentifier(node)) {
|
|
78
|
+
const scope = context.getScope();
|
|
79
|
+
const scopeId = getScopeId(scope);
|
|
80
|
+
const variable = scope.variables.find(v => v.name === node.name);
|
|
81
|
+
if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
82
|
+
const init = variable.defs[0].node.init;
|
|
83
|
+
if (init) {
|
|
84
|
+
if (isObjectExpression(init)) {
|
|
85
|
+
return init;
|
|
86
|
+
}
|
|
87
|
+
if (isFunction(init) || isArray(init) || isClass(init) || isPromise(init) || isPrimitive(init)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Check objects in the current scope
|
|
93
|
+
const scopeObjects = scopeMap.get(scopeId);
|
|
94
|
+
if (scopeObjects) {
|
|
95
|
+
for (const obj of scopeObjects) {
|
|
96
|
+
const info = objectMap.get(obj);
|
|
97
|
+
if (info && info.scope === scopeId && !info.isCircular) {
|
|
98
|
+
return obj;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (node.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
104
|
+
const property = node.property;
|
|
105
|
+
if (property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
106
|
+
const object = node.object;
|
|
107
|
+
if (isIdentifier(object)) {
|
|
108
|
+
const scope = context.getScope();
|
|
109
|
+
const variable = scope.variables.find(v => v.name === object.name);
|
|
110
|
+
if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
111
|
+
const init = variable.defs[0].node.init;
|
|
112
|
+
if (init) {
|
|
113
|
+
if (isObjectExpression(init)) {
|
|
114
|
+
// Check if we're accessing a property that's a primitive or function
|
|
115
|
+
const prop = init.properties.find(p => p.type === utils_1.AST_NODE_TYPES.Property &&
|
|
116
|
+
p.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
117
|
+
p.key.name === property.name);
|
|
118
|
+
if (prop?.value) {
|
|
119
|
+
if (isFunction(prop.value) || isPrimitive(prop.value)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return init;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
function getObjectFromMemberExpression(node) {
|
|
133
|
+
let current = node;
|
|
134
|
+
while (current.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
135
|
+
current = current.object;
|
|
136
|
+
}
|
|
137
|
+
if (isIdentifier(current)) {
|
|
138
|
+
return getReferencedObject(current);
|
|
139
|
+
}
|
|
140
|
+
if (isThisExpression(current)) {
|
|
141
|
+
const scope = context.getScope();
|
|
142
|
+
const scopeId = getScopeId(scope);
|
|
143
|
+
const scopeObjects = scopeMap.get(scopeId);
|
|
144
|
+
if (scopeObjects) {
|
|
145
|
+
for (const obj of scopeObjects) {
|
|
146
|
+
const info = objectMap.get(obj);
|
|
147
|
+
if (info && info.scope === scopeId && !info.isCircular) {
|
|
148
|
+
return obj;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function detectCircularReference(currentNode, visited = new Set(), depth = 0) {
|
|
156
|
+
if (depth > 100)
|
|
157
|
+
return false; // Prevent infinite recursion
|
|
158
|
+
if (visited.has(currentNode)) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
const objectInfo = objectMap.get(currentNode);
|
|
162
|
+
if (!objectInfo) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
visited.add(currentNode);
|
|
166
|
+
for (const ref of objectInfo.references) {
|
|
167
|
+
const referencedObj = getReferencedObject(ref);
|
|
168
|
+
if (referencedObj && detectCircularReference(referencedObj, new Set(visited), depth + 1)) {
|
|
169
|
+
objectInfo.isCircular = true;
|
|
170
|
+
circularRefs.add(ref);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
function checkAndReportCircularReference(targetObj, reference) {
|
|
177
|
+
const targetInfo = objectMap.get(targetObj);
|
|
178
|
+
if (targetInfo) {
|
|
179
|
+
targetInfo.references.add(reference);
|
|
180
|
+
if (detectCircularReference(targetObj)) {
|
|
181
|
+
context.report({
|
|
182
|
+
node: reference,
|
|
183
|
+
messageId: 'circularReference',
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
ObjectExpression(node) {
|
|
190
|
+
const scope = context.getScope();
|
|
191
|
+
const scopeId = getScopeId(scope);
|
|
192
|
+
objectMap.set(node, { node, references: new Set(), scope: scopeId });
|
|
193
|
+
let scopeObjects = scopeMap.get(scopeId);
|
|
194
|
+
if (!scopeObjects) {
|
|
195
|
+
scopeObjects = new Set();
|
|
196
|
+
scopeMap.set(scopeId, scopeObjects);
|
|
197
|
+
}
|
|
198
|
+
scopeObjects.add(node);
|
|
199
|
+
},
|
|
200
|
+
'ObjectExpression > Property'(node) {
|
|
201
|
+
const parentObject = node.parent;
|
|
202
|
+
const value = node.value;
|
|
203
|
+
if (isIdentifier(value)) {
|
|
204
|
+
const referencedObj = getReferencedObject(value);
|
|
205
|
+
if (referencedObj) {
|
|
206
|
+
checkAndReportCircularReference(parentObject, value);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
'AssignmentExpression'(node) {
|
|
211
|
+
if (node.right.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
212
|
+
const referencedObj = getReferencedObject(node.right);
|
|
213
|
+
if (referencedObj && node.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
214
|
+
const targetObj = getObjectFromMemberExpression(node.left);
|
|
215
|
+
if (targetObj) {
|
|
216
|
+
checkAndReportCircularReference(targetObj, node.right);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (node.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
221
|
+
const referencedObj = getObjectFromMemberExpression(node.right);
|
|
222
|
+
if (referencedObj && node.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
223
|
+
const targetObj = getObjectFromMemberExpression(node.left);
|
|
224
|
+
if (targetObj) {
|
|
225
|
+
checkAndReportCircularReference(targetObj, node.right);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
'VariableDeclarator'(node) {
|
|
231
|
+
if (node.init?.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
|
|
232
|
+
const properties = node.init.properties;
|
|
233
|
+
for (const prop of properties) {
|
|
234
|
+
if (prop.type === utils_1.AST_NODE_TYPES.Property && prop.value.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
235
|
+
const referencedObj = getReferencedObject(prop.value);
|
|
236
|
+
if (referencedObj) {
|
|
237
|
+
checkAndReportCircularReference(node.init, prop.value);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
'MethodDefinition'(node) {
|
|
244
|
+
if (node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
245
|
+
const body = node.value.body;
|
|
246
|
+
if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
247
|
+
for (const stmt of body.body) {
|
|
248
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
249
|
+
const assignment = stmt.expression;
|
|
250
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
251
|
+
const targetObj = getObjectFromMemberExpression(assignment.left);
|
|
252
|
+
if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
253
|
+
const referencedObj = getReferencedObject(assignment.right);
|
|
254
|
+
if (targetObj && referencedObj) {
|
|
255
|
+
const leftProperty = assignment.left.property;
|
|
256
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
257
|
+
const rightObj = getReferencedObject(assignment.right);
|
|
258
|
+
if (rightObj) {
|
|
259
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
265
|
+
const referencedObj = getObjectFromMemberExpression(assignment.right);
|
|
266
|
+
if (targetObj && referencedObj) {
|
|
267
|
+
const leftProperty = assignment.left.property;
|
|
268
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
269
|
+
const rightObj = getObjectFromMemberExpression(assignment.right);
|
|
270
|
+
if (rightObj) {
|
|
271
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
'ClassDeclaration'(node) {
|
|
283
|
+
const scope = context.getScope();
|
|
284
|
+
const scopeId = getScopeId(scope);
|
|
285
|
+
objectMap.set(node, { node, references: new Set(), scope: scopeId });
|
|
286
|
+
let scopeObjects = scopeMap.get(scopeId);
|
|
287
|
+
if (!scopeObjects) {
|
|
288
|
+
scopeObjects = new Set();
|
|
289
|
+
scopeMap.set(scopeId, scopeObjects);
|
|
290
|
+
}
|
|
291
|
+
scopeObjects.add(node);
|
|
292
|
+
// Check for circular references in constructor
|
|
293
|
+
const constructor = node.body.body.find(member => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
294
|
+
member.kind === 'constructor');
|
|
295
|
+
if (constructor) {
|
|
296
|
+
const body = constructor.value.body;
|
|
297
|
+
if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
298
|
+
for (const stmt of body.body) {
|
|
299
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
300
|
+
const assignment = stmt.expression;
|
|
301
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
302
|
+
const targetObj = getObjectFromMemberExpression(assignment.left);
|
|
303
|
+
if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
304
|
+
const referencedObj = getReferencedObject(assignment.right);
|
|
305
|
+
if (targetObj && referencedObj) {
|
|
306
|
+
const leftProperty = assignment.left.property;
|
|
307
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
308
|
+
const rightObj = getReferencedObject(assignment.right);
|
|
309
|
+
if (rightObj) {
|
|
310
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
316
|
+
const referencedObj = getObjectFromMemberExpression(assignment.right);
|
|
317
|
+
if (targetObj && referencedObj) {
|
|
318
|
+
const leftProperty = assignment.left.property;
|
|
319
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
320
|
+
const rightObj = getObjectFromMemberExpression(assignment.right);
|
|
321
|
+
if (rightObj) {
|
|
322
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
'ClassExpression'(node) {
|
|
334
|
+
const scope = context.getScope();
|
|
335
|
+
const scopeId = getScopeId(scope);
|
|
336
|
+
objectMap.set(node, { node, references: new Set(), scope: scopeId });
|
|
337
|
+
let scopeObjects = scopeMap.get(scopeId);
|
|
338
|
+
if (!scopeObjects) {
|
|
339
|
+
scopeObjects = new Set();
|
|
340
|
+
scopeMap.set(scopeId, scopeObjects);
|
|
341
|
+
}
|
|
342
|
+
scopeObjects.add(node);
|
|
343
|
+
// Check for circular references in constructor
|
|
344
|
+
const constructor = node.body.body.find(member => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
345
|
+
member.kind === 'constructor');
|
|
346
|
+
if (constructor) {
|
|
347
|
+
const body = constructor.value.body;
|
|
348
|
+
if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
349
|
+
for (const stmt of body.body) {
|
|
350
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
351
|
+
const assignment = stmt.expression;
|
|
352
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
353
|
+
const targetObj = getObjectFromMemberExpression(assignment.left);
|
|
354
|
+
if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
355
|
+
const referencedObj = getReferencedObject(assignment.right);
|
|
356
|
+
if (targetObj && referencedObj) {
|
|
357
|
+
const leftProperty = assignment.left.property;
|
|
358
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
359
|
+
const rightObj = getReferencedObject(assignment.right);
|
|
360
|
+
if (rightObj) {
|
|
361
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
367
|
+
const referencedObj = getObjectFromMemberExpression(assignment.right);
|
|
368
|
+
if (targetObj && referencedObj) {
|
|
369
|
+
const leftProperty = assignment.left.property;
|
|
370
|
+
if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier && leftProperty.name === 'self') {
|
|
371
|
+
const rightObj = getObjectFromMemberExpression(assignment.right);
|
|
372
|
+
if (rightObj) {
|
|
373
|
+
checkAndReportCircularReference(targetObj, assignment.right);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
'NewExpression'(node) {
|
|
385
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
386
|
+
const scope = context.getScope();
|
|
387
|
+
const variable = scope.variables.find(v => node.callee.type === utils_1.AST_NODE_TYPES.Identifier && v.name === node.callee.name);
|
|
388
|
+
if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.ClassDeclaration) {
|
|
389
|
+
const classDecl = variable.defs[0].node;
|
|
390
|
+
const constructor = classDecl.body.body.find(member => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
391
|
+
member.kind === 'constructor');
|
|
392
|
+
if (constructor) {
|
|
393
|
+
const body = constructor.value.body;
|
|
394
|
+
if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
395
|
+
for (const stmt of body.body) {
|
|
396
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
397
|
+
const assignment = stmt.expression;
|
|
398
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
399
|
+
const leftObj = assignment.left.object;
|
|
400
|
+
if (leftObj.type === utils_1.AST_NODE_TYPES.ThisExpression) {
|
|
401
|
+
if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
402
|
+
const referencedObj = getReferencedObject(assignment.right);
|
|
403
|
+
if (referencedObj) {
|
|
404
|
+
checkAndReportCircularReference(node, assignment.right);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
408
|
+
const referencedObj = getObjectFromMemberExpression(assignment.right);
|
|
409
|
+
if (referencedObj) {
|
|
410
|
+
checkAndReportCircularReference(node, assignment.right);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
'CallExpression'(node) {
|
|
423
|
+
if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
424
|
+
const obj = node.callee.object;
|
|
425
|
+
const prop = node.callee.property;
|
|
426
|
+
if (isIdentifier(obj) && isIdentifier(prop) && prop.name === 'then') {
|
|
427
|
+
// Handle Promise.then() calls
|
|
428
|
+
const scope = context.getScope();
|
|
429
|
+
const variable = scope.variables.find(v => v.name === obj.name);
|
|
430
|
+
if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
431
|
+
const init = variable.defs[0].node.init;
|
|
432
|
+
if (init && init.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
433
|
+
const callee = init.callee;
|
|
434
|
+
if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
435
|
+
const calleeObj = callee.object;
|
|
436
|
+
const calleeProp = callee.property;
|
|
437
|
+
if (isIdentifier(calleeObj) && isIdentifier(calleeProp) && calleeObj.name === 'Promise' && calleeProp.name === 'resolve') {
|
|
438
|
+
// This is a Promise.resolve() call
|
|
439
|
+
if (init.arguments.length > 0 && init.arguments[0].type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
440
|
+
const arg = init.arguments[0];
|
|
441
|
+
const referencedObj = getReferencedObject(arg);
|
|
442
|
+
if (referencedObj) {
|
|
443
|
+
// Check if the promise callback assigns the resolved value back to the original object
|
|
444
|
+
if (node.arguments.length > 0 && node.arguments[0].type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
445
|
+
const callback = node.arguments[0];
|
|
446
|
+
if (callback.body.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
447
|
+
const assignment = callback.body;
|
|
448
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
449
|
+
const leftObj = assignment.left.object;
|
|
450
|
+
if (isIdentifier(leftObj)) {
|
|
451
|
+
const leftObjRef = getReferencedObject(leftObj);
|
|
452
|
+
if (leftObjRef === referencedObj) {
|
|
453
|
+
context.report({
|
|
454
|
+
node: assignment,
|
|
455
|
+
messageId: 'circularReference',
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
else if (callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
462
|
+
for (const stmt of callback.body.body) {
|
|
463
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement && stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
464
|
+
const assignment = stmt.expression;
|
|
465
|
+
if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
466
|
+
const leftObj = assignment.left.object;
|
|
467
|
+
if (isIdentifier(leftObj)) {
|
|
468
|
+
const leftObjRef = getReferencedObject(leftObj);
|
|
469
|
+
if (leftObjRef === referencedObj) {
|
|
470
|
+
context.report({
|
|
471
|
+
node: assignment,
|
|
472
|
+
messageId: 'circularReference',
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
'MemberExpression'(node) {
|
|
491
|
+
if (node.parent && node.parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression && node.parent.left === node) {
|
|
492
|
+
return; // Skip left side of assignments, handled elsewhere
|
|
493
|
+
}
|
|
494
|
+
const obj = node.object;
|
|
495
|
+
const prop = node.property;
|
|
496
|
+
if (isIdentifier(obj) && isIdentifier(prop)) {
|
|
497
|
+
const referencedObj = getReferencedObject(obj);
|
|
498
|
+
if (referencedObj) {
|
|
499
|
+
const scope = context.getScope();
|
|
500
|
+
const scopeId = getScopeId(scope);
|
|
501
|
+
const info = objectMap.get(referencedObj);
|
|
502
|
+
if (info && info.scope === scopeId) {
|
|
503
|
+
// Check if this property access might lead to a circular reference
|
|
504
|
+
if (prop.name === 'self' || prop.name === 'ref' || prop.name === 'circular') {
|
|
505
|
+
const parent = node.parent;
|
|
506
|
+
if (parent && parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression && parent.right === node) {
|
|
507
|
+
const leftObj = getObjectFromMemberExpression(parent.left);
|
|
508
|
+
if (leftObj === referencedObj) {
|
|
509
|
+
context.report({
|
|
510
|
+
node,
|
|
511
|
+
messageId: 'circularReference',
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
};
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
//# sourceMappingURL=no-circular-references.js.map
|