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