@blumintinc/eslint-plugin-blumint 1.15.0 → 1.16.0

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.
Files changed (37) hide show
  1. package/README.md +28 -5
  2. package/lib/index.js +7 -1
  3. package/lib/rules/consistent-callback-naming.js +26 -0
  4. package/lib/rules/dynamic-https-errors.js +5 -26
  5. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +1 -0
  6. package/lib/rules/enforce-boolean-naming-prefixes.js +86 -119
  7. package/lib/rules/enforce-dynamic-imports.d.ts +2 -1
  8. package/lib/rules/enforce-dynamic-imports.js +42 -21
  9. package/lib/rules/enforce-memoize-async.js +1 -4
  10. package/lib/rules/enforce-mui-rounded-icons.js +42 -1
  11. package/lib/rules/enforce-verb-noun-naming.js +3 -0
  12. package/lib/rules/global-const-style.js +9 -0
  13. package/lib/rules/logical-top-to-bottom-grouping.js +80 -2
  14. package/lib/rules/memo-compare-deeply-complex-props.js +167 -3
  15. package/lib/rules/memo-nested-react-components.js +143 -8
  16. package/lib/rules/no-array-length-in-deps.js +74 -3
  17. package/lib/rules/no-circular-references.js +145 -482
  18. package/lib/rules/no-compositing-layer-props.js +31 -0
  19. package/lib/rules/no-entire-object-hook-deps.js +132 -97
  20. package/lib/rules/no-explicit-return-type.js +6 -0
  21. package/lib/rules/no-hungarian.js +119 -24
  22. package/lib/rules/no-margin-properties.js +7 -38
  23. package/lib/rules/no-unnecessary-verb-suffix.js +79 -0
  24. package/lib/rules/no-unused-props.js +215 -37
  25. package/lib/rules/no-useless-fragment.js +10 -2
  26. package/lib/rules/parallelize-async-operations.js +1 -3
  27. package/lib/rules/prefer-type-alias-over-typeof-constant.js +73 -11
  28. package/lib/rules/prefer-use-deep-compare-memo.js +8 -14
  29. package/lib/rules/react-memoize-literals.js +87 -1
  30. package/lib/rules/require-migration-script-metadata.d.ts +9 -0
  31. package/lib/rules/require-migration-script-metadata.js +206 -0
  32. package/lib/rules/warn-https-error-message-user-friendly.d.ts +1 -0
  33. package/lib/rules/warn-https-error-message-user-friendly.js +239 -0
  34. package/lib/utils/ASTHelpers.d.ts +15 -0
  35. package/lib/utils/ASTHelpers.js +48 -0
  36. package/package.json +7 -6
  37. package/release-manifest.json +166 -0
@@ -2,10 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.noCircularReferences = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
+ const ASTHelpers_1 = require("../utils/ASTHelpers");
5
6
  const createRule_1 = require("../utils/createRule");
6
- const objectMap = new WeakMap();
7
- const scopeMap = new Map();
8
- const circularRefs = new WeakSet();
9
7
  exports.noCircularReferences = (0, createRule_1.createRule)({
10
8
  name: 'no-circular-references',
11
9
  meta: {
@@ -22,6 +20,7 @@ exports.noCircularReferences = (0, createRule_1.createRule)({
22
20
  defaultOptions: [],
23
21
  create(context) {
24
22
  const sourceCode = context.getSourceCode();
23
+ const objectMap = new WeakMap();
25
24
  function reportCircularReference(node, reference) {
26
25
  context.report({
27
26
  node,
@@ -31,157 +30,114 @@ exports.noCircularReferences = (0, createRule_1.createRule)({
31
30
  },
32
31
  });
33
32
  }
34
- function isObjectExpression(node) {
35
- return node.type === utils_1.AST_NODE_TYPES.ObjectExpression;
33
+ function getUnwrappedObjectOrArray(node) {
34
+ const current = ASTHelpers_1.ASTHelpers.unwrapTSAssertions(node);
35
+ return current.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
36
+ current.type === utils_1.AST_NODE_TYPES.ArrayExpression
37
+ ? current
38
+ : null;
36
39
  }
37
40
  function isIdentifier(node) {
38
41
  return node.type === utils_1.AST_NODE_TYPES.Identifier;
39
42
  }
40
- function isThisExpression(node) {
41
- return node.type === utils_1.AST_NODE_TYPES.ThisExpression;
42
- }
43
- function getScopeId(scope) {
44
- return `${scope.type}:${scope.block.range[0]}:${scope.block.range[1]}`;
45
- }
46
43
  function isFunction(node) {
47
44
  return (node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
48
45
  node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
49
46
  node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration);
50
47
  }
51
- function isArray(node) {
52
- return (node.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
53
- node.type === utils_1.AST_NODE_TYPES.ArrayPattern);
54
- }
55
- function isClass(node) {
56
- return (node.type === utils_1.AST_NODE_TYPES.ClassExpression ||
57
- node.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
58
- node.type === utils_1.AST_NODE_TYPES.NewExpression);
59
- }
60
- function isPromise(node) {
61
- if (node.type === utils_1.AST_NODE_TYPES.CallExpression) {
62
- const callee = node.callee;
63
- if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
64
- return (callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
65
- callee.object.name === 'Promise' &&
66
- callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
67
- callee.property.name === 'resolve');
68
- }
69
- }
70
- return false;
71
- }
72
48
  function isPrimitive(node) {
73
- return (node.type === utils_1.AST_NODE_TYPES.Literal ||
74
- (node.type === utils_1.AST_NODE_TYPES.Identifier &&
75
- (node.name === 'undefined' || node.name === 'null')) ||
76
- node.type === utils_1.AST_NODE_TYPES.SpreadElement ||
77
- node.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
78
- node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
79
- (node.type === utils_1.AST_NODE_TYPES.CallExpression &&
80
- node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
81
- node.callee.name === 'fn') ||
82
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
83
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
84
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
85
- (node.property.name === 'a' ||
86
- node.property.name === 'b' ||
87
- node.property.name === 'c' ||
88
- node.property.name === 'd')) ||
89
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
90
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
91
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
92
- node.property.name === 'func') ||
93
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
94
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
95
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
96
- node.property.name === 'self') ||
97
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
98
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
99
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
100
- node.property.name === 'promise') ||
101
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
102
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
103
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
104
- node.property.name === 'ref') ||
105
- (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
106
- node.object.type === utils_1.AST_NODE_TYPES.Identifier &&
107
- node.property.type === utils_1.AST_NODE_TYPES.Identifier &&
108
- node.property.name === 'method'));
49
+ // Unwrap TS assertions (e.g. `undefined as unknown`) before checking primitiveness.
50
+ const unwrapped = ASTHelpers_1.ASTHelpers.unwrapTSAssertions(node);
51
+ if (unwrapped.type === utils_1.AST_NODE_TYPES.Literal)
52
+ return true;
53
+ if (isIdentifier(unwrapped) &&
54
+ (unwrapped.name === 'undefined' || unwrapped.name === 'null'))
55
+ return true;
56
+ return false;
109
57
  }
110
- function getVariable(name) {
111
- let scope = context.getScope();
58
+ function getVariable(node) {
59
+ let scope = ASTHelpers_1.ASTHelpers.getScope(context, node);
112
60
  while (scope) {
113
- const variable = scope.variables.find((v) => v.name === name);
114
- if (variable) {
61
+ const variable = scope.variables.find((v) => v.name === node.name);
62
+ if (variable)
115
63
  return variable;
116
- }
117
64
  scope = scope.upper;
118
65
  }
119
66
  return null;
120
67
  }
121
- function getReferencedObject(node) {
122
- if (isIdentifier(node)) {
123
- const variable = getVariable(node.name);
124
- if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
125
- const init = variable.defs[0].node.init;
126
- if (init) {
127
- if (isObjectExpression(init)) {
128
- return init;
129
- }
130
- if (isFunction(init) ||
131
- isArray(init) ||
132
- isClass(init) ||
133
- isPromise(init) ||
134
- isPrimitive(init)) {
135
- return null;
136
- }
68
+ function getReferencedObject(node, visitedVariables = new Set(), visitedNodes = new Set()) {
69
+ const current = ASTHelpers_1.ASTHelpers.unwrapTSAssertions(node);
70
+ if (visitedNodes.has(current))
71
+ return null;
72
+ visitedNodes.add(current);
73
+ if (current.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
74
+ current.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
75
+ return current;
76
+ }
77
+ if (isIdentifier(current)) {
78
+ const variable = getVariable(current);
79
+ if (variable &&
80
+ !visitedVariables.has(variable) &&
81
+ variable.defs.length > 0) {
82
+ visitedVariables.add(variable);
83
+ const def = variable.defs[0];
84
+ if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
85
+ def.node.init) {
86
+ const result = getReferencedObject(def.node.init, visitedVariables, visitedNodes);
87
+ if (result)
88
+ return result;
137
89
  }
138
90
  }
139
91
  }
140
- else if (node.type === utils_1.AST_NODE_TYPES.MemberExpression) {
141
- const property = node.property;
142
- if (property.type === utils_1.AST_NODE_TYPES.Identifier) {
143
- const object = node.object;
144
- if (isIdentifier(object)) {
145
- const variable = getVariable(object.name);
146
- if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
147
- const init = variable.defs[0].node.init;
148
- if (init) {
149
- if (isObjectExpression(init)) {
150
- // Check if we're accessing a property that's a primitive or function
151
- const prop = init.properties.find((p) => p.type === utils_1.AST_NODE_TYPES.Property &&
152
- p.key.type === utils_1.AST_NODE_TYPES.Identifier &&
153
- p.key.name === property.name);
154
- if (prop?.value) {
155
- if (isFunction(prop.value) || isPrimitive(prop.value)) {
156
- return null;
157
- }
158
- }
159
- return init;
160
- }
92
+ else if (current.type === utils_1.AST_NODE_TYPES.MemberExpression) {
93
+ const object = current.object;
94
+ const property = current.property;
95
+ const referencedObj = getReferencedObject(object, visitedVariables, visitedNodes);
96
+ if (referencedObj) {
97
+ const info = objectMap.get(referencedObj);
98
+ let propValue;
99
+ const key = !current.computed && isIdentifier(property)
100
+ ? property.name
101
+ : current.computed && property.type === utils_1.AST_NODE_TYPES.Literal
102
+ ? property.value
103
+ : null;
104
+ if (key !== null &&
105
+ (typeof key === 'string' || typeof key === 'number')) {
106
+ // 1. Check assigned properties first (overrides literal properties)
107
+ if (info) {
108
+ propValue = info.assignedProperties.get(key);
109
+ }
110
+ // 2. Check object literal properties
111
+ if (!propValue &&
112
+ referencedObj.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
113
+ const prop = referencedObj.properties.find((p) => p.type === utils_1.AST_NODE_TYPES.Property &&
114
+ !p.computed &&
115
+ ((isIdentifier(p.key) && p.key.name === key) ||
116
+ (p.key.type === utils_1.AST_NODE_TYPES.Literal &&
117
+ p.key.value === key)));
118
+ if (prop)
119
+ propValue = prop.value;
120
+ }
121
+ // 3. Check array literal elements
122
+ if (!propValue &&
123
+ referencedObj.type === utils_1.AST_NODE_TYPES.ArrayExpression &&
124
+ typeof key === 'number') {
125
+ const element = referencedObj.elements[key];
126
+ if (element && element.type !== utils_1.AST_NODE_TYPES.SpreadElement) {
127
+ propValue = element;
161
128
  }
162
129
  }
163
130
  }
164
- }
165
- }
166
- return null;
167
- }
168
- function getObjectFromMemberExpression(node) {
169
- let current = node;
170
- while (current.type === utils_1.AST_NODE_TYPES.MemberExpression) {
171
- current = current.object;
172
- }
173
- if (isIdentifier(current)) {
174
- return getReferencedObject(current);
175
- }
176
- if (isThisExpression(current)) {
177
- const scope = context.getScope();
178
- const scopeId = getScopeId(scope);
179
- const scopeObjects = scopeMap.get(scopeId);
180
- if (scopeObjects) {
181
- for (const obj of scopeObjects) {
182
- const info = objectMap.get(obj);
183
- if (info && info.scope === scopeId && !info.isCircular) {
184
- return obj;
131
+ if (propValue) {
132
+ const unwrappedValue = getUnwrappedObjectOrArray(propValue);
133
+ if (unwrappedValue)
134
+ return unwrappedValue;
135
+ if (isIdentifier(propValue) ||
136
+ propValue.type === utils_1.AST_NODE_TYPES.MemberExpression) {
137
+ return getReferencedObject(propValue, visitedVariables, visitedNodes);
138
+ }
139
+ if (isFunction(propValue) || isPrimitive(propValue)) {
140
+ return null;
185
141
  }
186
142
  }
187
143
  }
@@ -189,392 +145,99 @@ exports.noCircularReferences = (0, createRule_1.createRule)({
189
145
  return null;
190
146
  }
191
147
  function detectCircularReference(currentNode, visited = new Set(), depth = 0) {
192
- if (depth > 100)
193
- return false; // Prevent infinite recursion
194
- if (visited.has(currentNode)) {
148
+ if (depth > 50)
149
+ return false;
150
+ if (visited.has(currentNode))
195
151
  return true;
196
- }
197
152
  const objectInfo = objectMap.get(currentNode);
198
- if (!objectInfo) {
153
+ if (!objectInfo)
199
154
  return false;
200
- }
201
155
  visited.add(currentNode);
202
156
  for (const ref of objectInfo.references) {
203
157
  const referencedObj = getReferencedObject(ref);
204
158
  if (referencedObj &&
205
159
  detectCircularReference(referencedObj, new Set(visited), depth + 1)) {
206
- objectInfo.isCircular = true;
207
- circularRefs.add(ref);
208
160
  return true;
209
161
  }
210
162
  }
211
163
  return false;
212
164
  }
213
165
  function checkAndReportCircularReference(targetObj, reference) {
214
- const targetInfo = objectMap.get(targetObj);
166
+ const unwrapped = getUnwrappedObjectOrArray(targetObj);
167
+ if (!unwrapped)
168
+ return;
169
+ const targetInfo = objectMap.get(unwrapped);
215
170
  if (targetInfo) {
216
171
  targetInfo.references.add(reference);
217
- if (detectCircularReference(targetObj)) {
172
+ if (detectCircularReference(unwrapped)) {
218
173
  reportCircularReference(reference, reference);
219
174
  }
220
175
  }
221
176
  }
222
177
  return {
223
178
  ObjectExpression(node) {
224
- const scope = context.getScope();
225
- const scopeId = getScopeId(scope);
226
- objectMap.set(node, { node, references: new Set(), scope: scopeId });
227
- let scopeObjects = scopeMap.get(scopeId);
228
- if (!scopeObjects) {
229
- scopeObjects = new Set();
230
- scopeMap.set(scopeId, scopeObjects);
179
+ objectMap.set(node, {
180
+ references: new Set(),
181
+ assignedProperties: new Map(),
182
+ });
183
+ },
184
+ ArrayExpression(node) {
185
+ objectMap.set(node, {
186
+ references: new Set(),
187
+ assignedProperties: new Map(),
188
+ });
189
+ },
190
+ 'ArrayExpression > *'(node) {
191
+ if (!node || node.type === utils_1.AST_NODE_TYPES.SpreadElement)
192
+ return;
193
+ // Primitive values can never form circular references.
194
+ if (isPrimitive(node))
195
+ return;
196
+ const parentArray = node.parent;
197
+ const referencedObj = getReferencedObject(node);
198
+ if (referencedObj) {
199
+ checkAndReportCircularReference(parentArray, node);
231
200
  }
232
- scopeObjects.add(node);
233
201
  },
234
202
  'ObjectExpression > Property'(node) {
235
203
  const parentObject = node.parent;
236
204
  const value = node.value;
237
- if (isIdentifier(value)) {
238
- const referencedObj = getReferencedObject(value);
239
- if (referencedObj) {
240
- checkAndReportCircularReference(parentObject, value);
241
- }
205
+ // Primitive values (undefined, null, literals) can never form circular
206
+ // references, so skip them before any deeper resolution.
207
+ if (isPrimitive(value))
208
+ return;
209
+ const referencedObj = getReferencedObject(value);
210
+ if (referencedObj) {
211
+ checkAndReportCircularReference(parentObject, value);
242
212
  }
243
213
  },
244
214
  AssignmentExpression(node) {
245
- if (node.right.type === utils_1.AST_NODE_TYPES.Identifier) {
246
- const referencedObj = getReferencedObject(node.right);
247
- if (referencedObj &&
248
- node.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
249
- const targetObj = getObjectFromMemberExpression(node.left);
250
- if (targetObj) {
251
- checkAndReportCircularReference(targetObj, node.right);
252
- }
215
+ const right = node.right;
216
+ const left = node.left;
217
+ if (left.type !== utils_1.AST_NODE_TYPES.MemberExpression)
218
+ return;
219
+ const targetObj = getReferencedObject(left.object);
220
+ if (!targetObj)
221
+ return;
222
+ // Reassignments should override literal properties during resolution.
223
+ const targetInfo = objectMap.get(targetObj);
224
+ if (targetInfo) {
225
+ if (!left.computed && isIdentifier(left.property)) {
226
+ targetInfo.assignedProperties.set(left.property.name, right);
253
227
  }
254
- }
255
- else if (node.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
256
- const referencedObj = getObjectFromMemberExpression(node.right);
257
- if (referencedObj &&
258
- node.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
259
- const targetObj = getObjectFromMemberExpression(node.left);
260
- if (targetObj) {
261
- checkAndReportCircularReference(targetObj, node.right);
262
- }
263
- }
264
- }
265
- },
266
- VariableDeclarator(node) {
267
- if (node.init?.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
268
- const properties = node.init.properties;
269
- for (const prop of properties) {
270
- if (prop.type === utils_1.AST_NODE_TYPES.Property &&
271
- prop.value.type === utils_1.AST_NODE_TYPES.Identifier) {
272
- const referencedObj = getReferencedObject(prop.value);
273
- if (referencedObj) {
274
- checkAndReportCircularReference(node.init, prop.value);
275
- }
228
+ else if (left.computed &&
229
+ left.property.type === utils_1.AST_NODE_TYPES.Literal) {
230
+ const key = left.property.value;
231
+ if (typeof key === 'string' || typeof key === 'number') {
232
+ targetInfo.assignedProperties.set(key, right);
276
233
  }
277
234
  }
278
235
  }
279
- },
280
- MethodDefinition(node) {
281
- if (node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
282
- const body = node.value.body;
283
- if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
284
- for (const stmt of body.body) {
285
- if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
286
- stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
287
- const assignment = stmt.expression;
288
- if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
289
- const targetObj = getObjectFromMemberExpression(assignment.left);
290
- if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
291
- const referencedObj = getReferencedObject(assignment.right);
292
- if (targetObj && referencedObj) {
293
- const leftProperty = assignment.left.property;
294
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
295
- leftProperty.name === 'self') {
296
- const rightObj = getReferencedObject(assignment.right);
297
- if (rightObj) {
298
- checkAndReportCircularReference(targetObj, assignment.right);
299
- }
300
- }
301
- }
302
- }
303
- else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
304
- const referencedObj = getObjectFromMemberExpression(assignment.right);
305
- if (targetObj && referencedObj) {
306
- const leftProperty = assignment.left.property;
307
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
308
- leftProperty.name === 'self') {
309
- const rightObj = getObjectFromMemberExpression(assignment.right);
310
- if (rightObj) {
311
- checkAndReportCircularReference(targetObj, assignment.right);
312
- }
313
- }
314
- }
315
- }
316
- }
317
- }
318
- }
319
- }
320
- }
321
- },
322
- ClassDeclaration(node) {
323
- const scope = context.getScope();
324
- const scopeId = getScopeId(scope);
325
- objectMap.set(node, { node, references: new Set(), scope: scopeId });
326
- let scopeObjects = scopeMap.get(scopeId);
327
- if (!scopeObjects) {
328
- scopeObjects = new Set();
329
- scopeMap.set(scopeId, scopeObjects);
330
- }
331
- scopeObjects.add(node);
332
- // Check for circular references in constructor
333
- const constructor = node.body.body.find((member) => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
334
- member.kind === 'constructor');
335
- if (constructor) {
336
- const body = constructor.value.body;
337
- if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
338
- for (const stmt of body.body) {
339
- if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
340
- stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
341
- const assignment = stmt.expression;
342
- if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
343
- const targetObj = getObjectFromMemberExpression(assignment.left);
344
- if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
345
- const referencedObj = getReferencedObject(assignment.right);
346
- if (targetObj && referencedObj) {
347
- const leftProperty = assignment.left.property;
348
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
349
- leftProperty.name === 'self') {
350
- const rightObj = getReferencedObject(assignment.right);
351
- if (rightObj) {
352
- checkAndReportCircularReference(targetObj, assignment.right);
353
- }
354
- }
355
- }
356
- }
357
- else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
358
- const referencedObj = getObjectFromMemberExpression(assignment.right);
359
- if (targetObj && referencedObj) {
360
- const leftProperty = assignment.left.property;
361
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
362
- leftProperty.name === 'self') {
363
- const rightObj = getObjectFromMemberExpression(assignment.right);
364
- if (rightObj) {
365
- checkAndReportCircularReference(targetObj, assignment.right);
366
- }
367
- }
368
- }
369
- }
370
- }
371
- }
372
- }
373
- }
374
- }
375
- },
376
- ClassExpression(node) {
377
- const scope = context.getScope();
378
- const scopeId = getScopeId(scope);
379
- objectMap.set(node, { node, references: new Set(), scope: scopeId });
380
- let scopeObjects = scopeMap.get(scopeId);
381
- if (!scopeObjects) {
382
- scopeObjects = new Set();
383
- scopeMap.set(scopeId, scopeObjects);
384
- }
385
- scopeObjects.add(node);
386
- // Check for circular references in constructor
387
- const constructor = node.body.body.find((member) => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
388
- member.kind === 'constructor');
389
- if (constructor) {
390
- const body = constructor.value.body;
391
- if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
392
- for (const stmt of body.body) {
393
- if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
394
- stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
395
- const assignment = stmt.expression;
396
- if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
397
- const targetObj = getObjectFromMemberExpression(assignment.left);
398
- if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
399
- const referencedObj = getReferencedObject(assignment.right);
400
- if (targetObj && referencedObj) {
401
- const leftProperty = assignment.left.property;
402
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
403
- leftProperty.name === 'self') {
404
- const rightObj = getReferencedObject(assignment.right);
405
- if (rightObj) {
406
- checkAndReportCircularReference(targetObj, assignment.right);
407
- }
408
- }
409
- }
410
- }
411
- else if (assignment.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
412
- const referencedObj = getObjectFromMemberExpression(assignment.right);
413
- if (targetObj && referencedObj) {
414
- const leftProperty = assignment.left.property;
415
- if (leftProperty.type === utils_1.AST_NODE_TYPES.Identifier &&
416
- leftProperty.name === 'self') {
417
- const rightObj = getObjectFromMemberExpression(assignment.right);
418
- if (rightObj) {
419
- checkAndReportCircularReference(targetObj, assignment.right);
420
- }
421
- }
422
- }
423
- }
424
- }
425
- }
426
- }
427
- }
428
- }
429
- },
430
- NewExpression(node) {
431
- if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
432
- const scope = context.getScope();
433
- const variable = scope.variables.find((v) => node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
434
- v.name === node.callee.name);
435
- if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.ClassDeclaration) {
436
- const classDecl = variable.defs[0].node;
437
- const constructor = classDecl.body.body.find((member) => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
438
- member.kind === 'constructor');
439
- if (constructor) {
440
- const body = constructor.value.body;
441
- if (body && body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
442
- for (const stmt of body.body) {
443
- if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
444
- stmt.expression.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
445
- const assignment = stmt.expression;
446
- if (assignment.left.type === utils_1.AST_NODE_TYPES.MemberExpression) {
447
- const leftObj = assignment.left.object;
448
- if (leftObj.type === utils_1.AST_NODE_TYPES.ThisExpression) {
449
- if (assignment.right.type === utils_1.AST_NODE_TYPES.Identifier) {
450
- const referencedObj = getReferencedObject(assignment.right);
451
- if (referencedObj) {
452
- checkAndReportCircularReference(node, assignment.right);
453
- }
454
- }
455
- else if (assignment.right.type ===
456
- utils_1.AST_NODE_TYPES.MemberExpression) {
457
- const referencedObj = getObjectFromMemberExpression(assignment.right);
458
- if (referencedObj) {
459
- checkAndReportCircularReference(node, assignment.right);
460
- }
461
- }
462
- }
463
- }
464
- }
465
- }
466
- }
467
- }
468
- }
469
- }
470
- },
471
- CallExpression(node) {
472
- if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
473
- const obj = node.callee.object;
474
- const prop = node.callee.property;
475
- if (isIdentifier(obj) && isIdentifier(prop) && prop.name === 'then') {
476
- // Handle Promise.then() calls
477
- const scope = context.getScope();
478
- const variable = scope.variables.find((v) => v.name === obj.name);
479
- if (variable?.defs[0]?.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
480
- const init = variable.defs[0].node.init;
481
- if (init && init.type === utils_1.AST_NODE_TYPES.CallExpression) {
482
- const callee = init.callee;
483
- if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
484
- const calleeObj = callee.object;
485
- const calleeProp = callee.property;
486
- if (isIdentifier(calleeObj) &&
487
- isIdentifier(calleeProp) &&
488
- calleeObj.name === 'Promise' &&
489
- calleeProp.name === 'resolve') {
490
- // This is a Promise.resolve() call
491
- if (init.arguments.length > 0 &&
492
- init.arguments[0].type === utils_1.AST_NODE_TYPES.Identifier) {
493
- const arg = init.arguments[0];
494
- const referencedObj = getReferencedObject(arg);
495
- if (referencedObj) {
496
- // Check if the promise callback assigns the resolved value back to the original object
497
- if (node.arguments.length > 0 &&
498
- node.arguments[0].type ===
499
- utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
500
- const callback = node.arguments[0];
501
- if (callback.body.type ===
502
- utils_1.AST_NODE_TYPES.AssignmentExpression) {
503
- const assignment = callback.body;
504
- if (assignment.left.type ===
505
- utils_1.AST_NODE_TYPES.MemberExpression) {
506
- const leftObj = assignment.left.object;
507
- if (isIdentifier(leftObj)) {
508
- const leftObjRef = getReferencedObject(leftObj);
509
- if (leftObjRef === referencedObj) {
510
- const reference = assignment.right;
511
- reportCircularReference(assignment, reference);
512
- }
513
- }
514
- }
515
- }
516
- else if (callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
517
- for (const stmt of callback.body.body) {
518
- if (stmt.type ===
519
- utils_1.AST_NODE_TYPES.ExpressionStatement &&
520
- stmt.expression.type ===
521
- utils_1.AST_NODE_TYPES.AssignmentExpression) {
522
- const assignment = stmt.expression;
523
- if (assignment.left.type ===
524
- utils_1.AST_NODE_TYPES.MemberExpression) {
525
- const leftObj = assignment.left.object;
526
- if (isIdentifier(leftObj)) {
527
- const leftObjRef = getReferencedObject(leftObj);
528
- if (leftObjRef === referencedObj) {
529
- const reference = assignment.right;
530
- reportCircularReference(assignment, reference);
531
- }
532
- }
533
- }
534
- }
535
- }
536
- }
537
- }
538
- }
539
- }
540
- }
541
- }
542
- }
543
- }
544
- }
545
- }
546
- },
547
- MemberExpression(node) {
548
- if (node.parent &&
549
- node.parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
550
- node.parent.left === node) {
551
- return; // Skip left side of assignments, handled elsewhere
552
- }
553
- const obj = node.object;
554
- const prop = node.property;
555
- if (isIdentifier(obj) && isIdentifier(prop)) {
556
- const referencedObj = getReferencedObject(obj);
236
+ // Primitive values on the right-hand side can never create circular references.
237
+ if (!isPrimitive(right)) {
238
+ const referencedObj = getReferencedObject(right);
557
239
  if (referencedObj) {
558
- const scope = context.getScope();
559
- const scopeId = getScopeId(scope);
560
- const info = objectMap.get(referencedObj);
561
- if (info && info.scope === scopeId) {
562
- // Check if this property access might lead to a circular reference
563
- if (prop.name === 'self' ||
564
- prop.name === 'ref' ||
565
- prop.name === 'circular') {
566
- const parent = node.parent;
567
- if (parent &&
568
- parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
569
- parent.right === node) {
570
- const leftObj = getObjectFromMemberExpression(parent.left);
571
- if (leftObj === referencedObj) {
572
- const reference = node;
573
- reportCircularReference(node, reference);
574
- }
575
- }
576
- }
577
- }
240
+ checkAndReportCircularReference(targetObj, right);
578
241
  }
579
242
  }
580
243
  },