@eslint-react/var 3.0.0-next.6 → 3.0.0-next.60

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 (3) hide show
  1. package/dist/index.d.ts +44 -76
  2. package/dist/index.js +115 -212
  3. package/package.json +6 -6
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { TSESTree } from "@typescript-eslint/types";
3
3
  import { Scope, Variable } from "@typescript-eslint/scope-manager";
4
4
  import { RuleContext } from "@eslint-react/shared";
5
5
 
6
- //#region src/var-assignment-target.d.ts
6
+ //#region src/find-enclosing-assignment-target.d.ts
7
7
  /**
8
8
  * Finds the enclosing assignment target (variable, property, etc.) for a given node
9
9
  *
@@ -16,54 +16,23 @@ declare function findEnclosingAssignmentTarget(node: TSESTree.Node): TSESTree.Ar
16
16
  * Type representing the possible assignment targets returned by `findEnclosingAssignmentTarget`
17
17
  */
18
18
  type AssignmentTarget = ReturnType<typeof findEnclosingAssignmentTarget>;
19
- /**
20
- * Check if two assignment targets are equal
21
- * Compares nodes directly or by their values
22
- * @param context The rule context
23
- * @param a The first node to compare
24
- * @param b The second node to compare
25
- * @returns True if the assignment targets are equal
26
- * @internal
27
- */
28
- declare function isAssignmentTargetEqual(context: RuleContext, a: TSESTree.Node, b: TSESTree.Node): boolean;
29
- //#endregion
30
- //#region src/var-definition.d.ts
31
- /**
32
- * Get the definition node of a variable at a specific definition index
33
- * @param variable The variable to get the definition node from
34
- * @param at The index of the definition to retrieve (negative index supported)
35
- * @returns The definition node or unit if not found
36
- */
37
- declare function getVariableDefinitionNode(variable: Variable | unit, at: number): unit | TSESTree.ClassDeclaration | TSESTree.ClassDeclarationWithName | TSESTree.ClassDeclarationWithOptionalName | TSESTree.Expression | TSESTree.FunctionDeclaration | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName;
38
- /**
39
- * Get the definition node of a variable at a specific definition index (loose version)
40
- * Also returns the function node if the definition is a parameter
41
- * @param variable The variable to get the definition node from
42
- * @param at The index of the definition to retrieve
43
- * @returns The definition node or unit if not found
44
- */
45
- declare function getVariableDefinitionNodeLoose(variable: Variable | unit, at: number): unit | TSESTree.ClassDeclaration | TSESTree.ClassDeclarationWithName | TSESTree.ClassDeclarationWithOptionalName | TSESTree.Expression | TSESTree.FunctionDeclaration | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName;
46
19
  //#endregion
47
- //#region src/var-import-source.d.ts
20
+ //#region src/find-variable.d.ts
48
21
  /**
49
- * Find the import source of a variable
50
- * @param name The variable name
51
- * @param initialScope The initial scope to search
52
- * @returns The import source or undefined if not found
53
- */
54
- declare function findImportSource(name: string, initialScope: Scope): string | undefined;
55
- //#endregion
56
- //#region src/var-node-equality.d.ts
57
- /**
58
- * Determine whether node value equals to another node value
59
- * @param a node to compare
60
- * @param b node to compare
61
- * @param initialScopes initial scopes of the two nodes
62
- * @returns `true` if node value equal
22
+ * Find a variable by name or identifier node in the scope chain
23
+ * @param initialScope The scope to start searching from
24
+ * @returns The found variable or unit if not found
25
+ * @overload
26
+ * @param nameOrNode The variable name or identifier node to find
27
+ * @param initialScope The scope to start searching from
28
+ * @returns The found variable or unit if not found
63
29
  */
64
- declare function isNodeEqual(a: TSESTree.Node, b: TSESTree.Node, initialScopes: [aScope: Scope, bScope: Scope]): boolean;
30
+ declare const findVariable: {
31
+ (initialScope: Scope): (nameOrNode: string | TSESTree.Identifier | unit) => Variable | unit;
32
+ (nameOrNode: string | TSESTree.Identifier | unit, initialScope: Scope): Variable | unit;
33
+ };
65
34
  //#endregion
66
- //#region src/var-object-type.d.ts
35
+ //#region src/get-object-type.d.ts
67
36
  /**
68
37
  * Represents the type classification of an object node
69
38
  */
@@ -101,43 +70,42 @@ type ObjectType = {
101
70
  */
102
71
  declare function getObjectType(node: TSESTree.Node | unit, initialScope: Scope): ObjectType | unit;
103
72
  //#endregion
104
- //#region src/var-property.d.ts
73
+ //#region src/get-variable-initializer.d.ts
105
74
  /**
106
- * Find a property by name in an array of properties
107
- * Handles spread elements by recursively resolving the referenced object
108
- * @param name The property name to find
109
- * @param properties The array of properties to search
110
- * @param initialScope The scope to use for variable resolution
111
- * @param seen Set of already seen variable names to prevent circular references
112
- * @returns The found property or unit if not found
75
+ * Get the initializer expression or statement of a variable definition at a specified index
76
+ * @param variable The variable to get the initializer from
77
+ * @param at The index of the variable definition to get the initializer from
78
+ * @returns The initializer expression or statement of the variable definition at the specified index, or unit if not found
113
79
  */
114
- declare function findProperty(name: string, properties: (TSESTree.Property | TSESTree.RestElement | TSESTree.SpreadElement)[], initialScope: Scope, seen?: Set<string>): (typeof properties)[number] | unit;
115
- //#endregion
116
- //#region src/var-scope.d.ts
80
+ declare function getVariableInitializer(variable: Variable | unit, at: number): unit | TSESTree.ClassDeclaration | TSESTree.Expression | TSESTree.FunctionDeclaration;
117
81
  /**
118
- * Get all variables from the given scope up to the global scope
119
- * @param initialScope The scope to start from
120
- * @returns All variables from the given scope up to the global scope
82
+ * Get the initializer expression or statement of a variable definition at a specified index, or the function declaration if the variable is a parameter of a function
83
+ * @param variable The variable to get the initializer from
84
+ * @param at The index of the variable definition to get the initializer from
85
+ * @returns The initializer expression or statement of the variable definition at the specified index, or the function declaration if the variable is a parameter of a function, or unit if not found
121
86
  */
122
- declare function getVariables(initialScope: Scope): Variable[];
87
+ declare function getVariableInitializerLoose(variable: Variable | unit, at: number): unit | TSESTree.ClassDeclaration | TSESTree.Expression | TSESTree.FunctionDeclaration;
88
+ //#endregion
89
+ //#region src/is-assignment-target-equal.d.ts
123
90
  /**
124
- * Find a variable by name or identifier node in the scope chain
125
- * @param initialScope The scope to start searching from
126
- * @returns The found variable or unit if not found
127
- * @overload
128
- * @param nameOrNode The variable name or identifier node to find
129
- * @param initialScope The scope to start searching from
130
- * @returns The found variable or unit if not found
91
+ * Check if two assignment targets are equal
92
+ * Compares nodes directly or by their values
93
+ * @param context The rule context
94
+ * @param a The first node to compare
95
+ * @param b The second node to compare
96
+ * @returns True if the assignment targets are equal
97
+ * @internal
131
98
  */
132
- declare const findVariable: {
133
- (initialScope: Scope): (nameOrNode: string | TSESTree.Identifier | unit) => Variable | unit;
134
- (nameOrNode: string | TSESTree.Identifier | unit, initialScope: Scope): Variable | unit;
135
- };
99
+ declare function isAssignmentTargetEqual(context: RuleContext, a: TSESTree.Node, b: TSESTree.Node): boolean;
100
+ //#endregion
101
+ //#region src/is-value-equal.d.ts
136
102
  /**
137
- * Get all child scopes recursively from a given scope
138
- * @param scope The scope to get child scopes from
139
- * @returns Array of all child scopes including the input scope
103
+ * Determine whether node value equals to another node value
104
+ * @param a node to compare
105
+ * @param b node to compare
106
+ * @param initialScopes initial scopes of the two nodes
107
+ * @returns `true` if node value equal
140
108
  */
141
- declare function getChildScopes(scope: Scope): readonly Scope[];
109
+ declare function isValueEqual(a: TSESTree.Node, b: TSESTree.Node, initialScopes: [aScope: Scope, bScope: Scope]): boolean;
142
110
  //#endregion
143
- export { AssignmentTarget, ObjectType, findEnclosingAssignmentTarget, findImportSource, findProperty, findVariable, getChildScopes, getObjectType, getVariableDefinitionNode, getVariableDefinitionNodeLoose, getVariables, isAssignmentTargetEqual, isNodeEqual };
111
+ export { AssignmentTarget, ObjectType, findEnclosingAssignmentTarget, findVariable, getObjectType, getVariableInitializer, getVariableInitializerLoose, isAssignmentTargetEqual, isValueEqual };
package/dist/index.js CHANGED
@@ -1,61 +1,30 @@
1
- import * as ast from "@eslint-react/ast";
2
- import { dual, identity, unit } from "@eslint-react/eff";
1
+ import { dual, unit } from "@eslint-react/eff";
3
2
  import { AST_NODE_TYPES } from "@typescript-eslint/types";
4
3
  import * as astUtils from "@typescript-eslint/utils/ast-utils";
5
4
  import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
6
- import { DefinitionType, ScopeType } from "@typescript-eslint/scope-manager";
7
- import { P, match } from "ts-pattern";
5
+ import * as ast from "@eslint-react/ast";
6
+ import { DefinitionType } from "@typescript-eslint/scope-manager";
8
7
 
9
- //#region src/var-definition.ts
8
+ //#region src/find-enclosing-assignment-target.ts
10
9
  /**
11
- * Get the definition node of a variable at a specific definition index
12
- * @param variable The variable to get the definition node from
13
- * @param at The index of the definition to retrieve (negative index supported)
14
- * @returns The definition node or unit if not found
10
+ * Finds the enclosing assignment target (variable, property, etc.) for a given node
11
+ *
12
+ * @todo Verify correctness and completeness of this function
13
+ * @param node The starting node
14
+ * @returns The enclosing assignment target node, or undefined if not found
15
15
  */
16
- function getVariableDefinitionNode(variable, at) {
17
- if (variable == null) return unit;
18
- const def = variable.defs.at(at);
19
- if (def == null) return unit;
16
+ function findEnclosingAssignmentTarget(node) {
20
17
  switch (true) {
21
- case def.type === DefinitionType.FunctionName && def.node.type === AST_NODE_TYPES.FunctionDeclaration: return def.node;
22
- case def.type === DefinitionType.ClassName && def.node.type === AST_NODE_TYPES.ClassDeclaration: return def.node;
23
- case "init" in def.node && def.node.init != null && !("declarations" in def.node.init): return def.node.init;
24
- default: return unit;
18
+ case node.type === AST_NODE_TYPES.VariableDeclarator: return node.id;
19
+ case node.type === AST_NODE_TYPES.AssignmentExpression: return node.left;
20
+ case node.type === AST_NODE_TYPES.PropertyDefinition: return node.key;
21
+ case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return unit;
22
+ default: return findEnclosingAssignmentTarget(node.parent);
25
23
  }
26
24
  }
27
- /**
28
- * Get the definition node of a variable at a specific definition index (loose version)
29
- * Also returns the function node if the definition is a parameter
30
- * @param variable The variable to get the definition node from
31
- * @param at The index of the definition to retrieve
32
- * @returns The definition node or unit if not found
33
- */
34
- function getVariableDefinitionNodeLoose(variable, at) {
35
- if (variable == null) return unit;
36
- const node = getVariableDefinitionNode(variable, at);
37
- if (node != null) return node;
38
- const def = variable.defs.at(at);
39
- if (def?.type === DefinitionType.Parameter && ast.isFunction(def.node)) return def.node;
40
- return unit;
41
- }
42
25
 
43
26
  //#endregion
44
- //#region src/var-scope.ts
45
- /**
46
- * Get all variables from the given scope up to the global scope
47
- * @param initialScope The scope to start from
48
- * @returns All variables from the given scope up to the global scope
49
- */
50
- function getVariables(initialScope) {
51
- let scope = initialScope;
52
- const variables = [...scope.variables];
53
- while (scope.type !== ScopeType.global) {
54
- scope = scope.upper;
55
- variables.push(...scope.variables);
56
- }
57
- return variables.reverse();
58
- }
27
+ //#region src/find-variable.ts
59
28
  /**
60
29
  * Find a variable by name or identifier node in the scope chain
61
30
  * @param initialScope The scope to start searching from
@@ -69,159 +38,43 @@ const findVariable = dual(2, (nameOrNode, initialScope) => {
69
38
  if (nameOrNode == null) return unit;
70
39
  return astUtils.findVariable(initialScope, nameOrNode) ?? unit;
71
40
  });
72
- /**
73
- * Get all child scopes recursively from a given scope
74
- * @param scope The scope to get child scopes from
75
- * @returns Array of all child scopes including the input scope
76
- */
77
- function getChildScopes(scope) {
78
- const scopes = [scope];
79
- for (const childScope of scope.childScopes) scopes.push(...getChildScopes(childScope));
80
- return scopes;
81
- }
82
41
 
83
42
  //#endregion
84
- //#region src/var-node-equality.ts
85
- const thisBlockTypes = [
86
- AST_NODE_TYPES.FunctionDeclaration,
87
- AST_NODE_TYPES.FunctionExpression,
88
- AST_NODE_TYPES.ClassBody,
89
- AST_NODE_TYPES.Program
90
- ];
43
+ //#region src/get-variable-initializer.ts
91
44
  /**
92
- * Determine whether node value equals to another node value
93
- * @param a node to compare
94
- * @param b node to compare
95
- * @param initialScopes initial scopes of the two nodes
96
- * @returns `true` if node value equal
97
- */
98
- function isNodeEqual(a, b, initialScopes) {
99
- a = ast.isTypeExpression(a) ? ast.getUnderlyingExpression(a) : a;
100
- b = ast.isTypeExpression(b) ? ast.getUnderlyingExpression(b) : b;
101
- const [aScope, bScope] = initialScopes;
102
- switch (true) {
103
- case a === b: return true;
104
- case a.type === AST_NODE_TYPES.Literal && b.type === AST_NODE_TYPES.Literal: return a.value === b.value;
105
- case a.type === AST_NODE_TYPES.TemplateElement && b.type === AST_NODE_TYPES.TemplateElement: return a.value.cooked === b.value.cooked;
106
- case a.type === AST_NODE_TYPES.Identifier && b.type === AST_NODE_TYPES.Identifier: {
107
- const aVar = findVariable(a, aScope);
108
- const bVar = findVariable(b, bScope);
109
- const aVarNode = getVariableDefinitionNodeLoose(aVar, 0);
110
- const bVarNode = getVariableDefinitionNodeLoose(bVar, 0);
111
- const aVarNodeParent = aVarNode?.parent;
112
- const bVarNodeParent = bVarNode?.parent;
113
- const aDef = aVar?.defs.at(0);
114
- const bDef = bVar?.defs.at(0);
115
- const aDefParentParent = aDef?.parent?.parent;
116
- const bDefParentParent = bDef?.parent?.parent;
117
- switch (true) {
118
- case aVarNodeParent?.type === AST_NODE_TYPES.CallExpression && bVarNodeParent?.type === AST_NODE_TYPES.CallExpression && ast.isFunction(aVarNode) && ast.isFunction(bVarNode): {
119
- if (!ast.isNodeEqual(aVarNodeParent.callee, bVarNodeParent.callee)) return false;
120
- const aParams = aVarNode.params;
121
- const bParams = bVarNode.params;
122
- const aPos = aParams.findIndex((x) => ast.isNodeEqual(x, a));
123
- const bPos = bParams.findIndex((x) => ast.isNodeEqual(x, b));
124
- return aPos !== -1 && bPos !== -1 && aPos === bPos;
125
- }
126
- case aDefParentParent?.type === AST_NODE_TYPES.ForOfStatement && bDefParentParent?.type === AST_NODE_TYPES.ForOfStatement: {
127
- const aLeft = aDefParentParent.left;
128
- const bLeft = bDefParentParent.left;
129
- if (aLeft.type !== bLeft.type) return false;
130
- const aRight = aDefParentParent.right;
131
- const bRight = bDefParentParent.right;
132
- return ast.isNodeEqual(aRight, bRight);
133
- }
134
- default: return aVar != null && bVar != null && aVar === bVar;
135
- }
136
- }
137
- case a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression: return ast.isNodeEqual(a.property, b.property) && isNodeEqual(a.object, b.object, initialScopes);
138
- case a.type === AST_NODE_TYPES.ThisExpression && b.type === AST_NODE_TYPES.ThisExpression:
139
- if (aScope.block === bScope.block) return true;
140
- return ast.findParentNode(a, ast.isOneOf(thisBlockTypes)) === ast.findParentNode(b, ast.isOneOf(thisBlockTypes));
141
- default: {
142
- const aStatic = getStaticValue(a, aScope);
143
- const bStatic = getStaticValue(b, bScope);
144
- return aStatic != null && bStatic != null && aStatic.value === bStatic.value;
145
- }
146
- }
147
- }
148
-
149
- //#endregion
150
- //#region src/var-assignment-target.ts
151
- /** eslint-disable jsdoc/require-param */
152
- /**
153
- * Finds the enclosing assignment target (variable, property, etc.) for a given node
154
- *
155
- * @todo Verify correctness and completeness of this function
156
- * @param node The starting node
157
- * @returns The enclosing assignment target node, or undefined if not found
45
+ * Get the initializer expression or statement of a variable definition at a specified index
46
+ * @param variable The variable to get the initializer from
47
+ * @param at The index of the variable definition to get the initializer from
48
+ * @returns The initializer expression or statement of the variable definition at the specified index, or unit if not found
158
49
  */
159
- function findEnclosingAssignmentTarget(node) {
50
+ function getVariableInitializer(variable, at) {
51
+ if (variable == null) return unit;
52
+ const def = variable.defs.at(at);
53
+ if (def == null) return unit;
160
54
  switch (true) {
161
- case node.type === AST_NODE_TYPES.VariableDeclarator: return node.id;
162
- case node.type === AST_NODE_TYPES.AssignmentExpression: return node.left;
163
- case node.type === AST_NODE_TYPES.PropertyDefinition: return node.key;
164
- case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return unit;
165
- default: return findEnclosingAssignmentTarget(node.parent);
55
+ case def.type === DefinitionType.FunctionName && def.node.type === AST_NODE_TYPES.FunctionDeclaration: return def.node;
56
+ case def.type === DefinitionType.ClassName && def.node.type === AST_NODE_TYPES.ClassDeclaration: return def.node;
57
+ case "init" in def.node && def.node.init != null && !("declarations" in def.node.init): return def.node.init;
58
+ default: return unit;
166
59
  }
167
60
  }
168
61
  /**
169
- * Check if two assignment targets are equal
170
- * Compares nodes directly or by their values
171
- * @param context The rule context
172
- * @param a The first node to compare
173
- * @param b The second node to compare
174
- * @returns True if the assignment targets are equal
175
- * @internal
176
- */
177
- function isAssignmentTargetEqual(context, a, b) {
178
- return ast.isNodeEqual(a, b) || isNodeEqual(a, b, [context.sourceCode.getScope(a), context.sourceCode.getScope(b)]);
179
- }
180
-
181
- //#endregion
182
- //#region src/var-import-source.ts
183
- /**
184
- * Get the arguments of a require expression
185
- * @param node The node to match
186
- * @returns The require expression arguments or undefined if the node is not a require expression
187
- */
188
- function getRequireExpressionArguments(node) {
189
- return match(node).with({
190
- type: AST_NODE_TYPES.CallExpression,
191
- arguments: P.select(),
192
- callee: {
193
- type: AST_NODE_TYPES.Identifier,
194
- name: "require"
195
- }
196
- }, identity).with({
197
- type: AST_NODE_TYPES.MemberExpression,
198
- object: P.select()
199
- }, getRequireExpressionArguments).otherwise(() => null);
200
- }
201
- /**
202
- * Find the import source of a variable
203
- * @param name The variable name
204
- * @param initialScope The initial scope to search
205
- * @returns The import source or undefined if not found
62
+ * Get the initializer expression or statement of a variable definition at a specified index, or the function declaration if the variable is a parameter of a function
63
+ * @param variable The variable to get the initializer from
64
+ * @param at The index of the variable definition to get the initializer from
65
+ * @returns The initializer expression or statement of the variable definition at the specified index, or the function declaration if the variable is a parameter of a function, or unit if not found
206
66
  */
207
- function findImportSource(name, initialScope) {
208
- const latestDef = findVariable(name, initialScope)?.defs.at(-1);
209
- if (latestDef == null) return unit;
210
- const { node, parent } = latestDef;
211
- if (node.type === AST_NODE_TYPES.VariableDeclarator && node.init != null) {
212
- const { init } = node;
213
- if (init.type === AST_NODE_TYPES.MemberExpression && init.object.type === AST_NODE_TYPES.Identifier) return findImportSource(init.object.name, initialScope);
214
- if (init.type === AST_NODE_TYPES.Identifier) return findImportSource(init.name, initialScope);
215
- const arg0 = getRequireExpressionArguments(init)?.[0];
216
- if (arg0 == null || !ast.isLiteral(arg0, "string")) return unit;
217
- return arg0.value;
218
- }
219
- if (parent?.type === AST_NODE_TYPES.ImportDeclaration) return parent.source.value;
67
+ function getVariableInitializerLoose(variable, at) {
68
+ if (variable == null) return unit;
69
+ const node = getVariableInitializer(variable, at);
70
+ if (node != null) return node;
71
+ const def = variable.defs.at(at);
72
+ if (def?.type === DefinitionType.Parameter && ast.isFunction(def.node)) return def.node;
220
73
  return unit;
221
74
  }
222
75
 
223
76
  //#endregion
224
- //#region src/var-object-type.ts
77
+ //#region src/get-object-type.ts
225
78
  /**
226
79
  * Detect the ObjectType of a given node
227
80
  * @param node The node to check
@@ -267,7 +120,7 @@ function getObjectType(node, initialScope) {
267
120
  return unit;
268
121
  case AST_NODE_TYPES.Identifier:
269
122
  if (!("name" in node) || typeof node.name !== "string") return unit;
270
- return getObjectType(getVariableDefinitionNode(initialScope.set.get(node.name), -1), initialScope);
123
+ return getObjectType(getVariableInitializer(initialScope.set.get(node.name), -1), initialScope);
271
124
  case AST_NODE_TYPES.MemberExpression:
272
125
  if (!("object" in node)) return unit;
273
126
  return getObjectType(node.object, initialScope);
@@ -292,35 +145,85 @@ function getObjectType(node, initialScope) {
292
145
  }
293
146
 
294
147
  //#endregion
295
- //#region src/var-property.ts
148
+ //#region src/is-value-equal.ts
149
+ const thisBlockTypes = [
150
+ AST_NODE_TYPES.FunctionDeclaration,
151
+ AST_NODE_TYPES.FunctionExpression,
152
+ AST_NODE_TYPES.ClassBody,
153
+ AST_NODE_TYPES.Program
154
+ ];
296
155
  /**
297
- * Find a property by name in an array of properties
298
- * Handles spread elements by recursively resolving the referenced object
299
- * @param name The property name to find
300
- * @param properties The array of properties to search
301
- * @param initialScope The scope to use for variable resolution
302
- * @param seen Set of already seen variable names to prevent circular references
303
- * @returns The found property or unit if not found
156
+ * Determine whether node value equals to another node value
157
+ * @param a node to compare
158
+ * @param b node to compare
159
+ * @param initialScopes initial scopes of the two nodes
160
+ * @returns `true` if node value equal
304
161
  */
305
- function findProperty(name, properties, initialScope, seen = /* @__PURE__ */ new Set()) {
306
- return properties.findLast((prop) => {
307
- if (prop.type === AST_NODE_TYPES.Property) return "name" in prop.key && prop.key.name === name;
308
- if (prop.type === AST_NODE_TYPES.SpreadElement) switch (prop.argument.type) {
309
- case AST_NODE_TYPES.Identifier: {
310
- if (seen.has(prop.argument.name)) return false;
311
- const variableNode = getVariableDefinitionNode(findVariable(prop.argument.name, initialScope), 0);
312
- if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) {
313
- seen.add(prop.argument.name);
314
- return findProperty(name, variableNode.properties, initialScope, seen) != null;
162
+ function isValueEqual(a, b, initialScopes) {
163
+ a = ast.isTypeExpression(a) ? ast.getUnderlyingExpression(a) : a;
164
+ b = ast.isTypeExpression(b) ? ast.getUnderlyingExpression(b) : b;
165
+ const [aScope, bScope] = initialScopes;
166
+ switch (true) {
167
+ case a === b: return true;
168
+ case a.type === AST_NODE_TYPES.Literal && b.type === AST_NODE_TYPES.Literal: return a.value === b.value;
169
+ case a.type === AST_NODE_TYPES.TemplateElement && b.type === AST_NODE_TYPES.TemplateElement: return a.value.cooked === b.value.cooked;
170
+ case a.type === AST_NODE_TYPES.Identifier && b.type === AST_NODE_TYPES.Identifier: {
171
+ const aVar = findVariable(a, aScope);
172
+ const bVar = findVariable(b, bScope);
173
+ const aVarInit = getVariableInitializerLoose(aVar, 0);
174
+ const bVarInit = getVariableInitializerLoose(bVar, 0);
175
+ const aVarInitParent = aVarInit?.parent;
176
+ const bVarInitParent = bVarInit?.parent;
177
+ const aDef = aVar?.defs.at(0);
178
+ const bDef = bVar?.defs.at(0);
179
+ const aDefParentParent = aDef?.parent?.parent;
180
+ const bDefParentParent = bDef?.parent?.parent;
181
+ switch (true) {
182
+ case aVarInitParent?.type === AST_NODE_TYPES.CallExpression && bVarInitParent?.type === AST_NODE_TYPES.CallExpression && ast.isFunction(aVarInit) && ast.isFunction(bVarInit): {
183
+ if (!ast.isNodeEqual(aVarInitParent.callee, bVarInitParent.callee)) return false;
184
+ const aParams = aVarInit.params;
185
+ const bParams = bVarInit.params;
186
+ const aPos = aParams.findIndex((x) => ast.isNodeEqual(x, a));
187
+ const bPos = bParams.findIndex((x) => ast.isNodeEqual(x, b));
188
+ return aPos !== -1 && bPos !== -1 && aPos === bPos;
189
+ }
190
+ case aDefParentParent?.type === AST_NODE_TYPES.ForOfStatement && bDefParentParent?.type === AST_NODE_TYPES.ForOfStatement: {
191
+ const aLeft = aDefParentParent.left;
192
+ const bLeft = bDefParentParent.left;
193
+ if (aLeft.type !== bLeft.type) return false;
194
+ const aRight = aDefParentParent.right;
195
+ const bRight = bDefParentParent.right;
196
+ return ast.isNodeEqual(aRight, bRight);
315
197
  }
316
- return false;
198
+ default: return aVar != null && bVar != null && aVar === bVar;
317
199
  }
318
- case AST_NODE_TYPES.ObjectExpression: return findProperty(name, prop.argument.properties, initialScope, seen) != null;
319
- default: return false;
320
200
  }
321
- return false;
322
- });
201
+ case a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression: return ast.isNodeEqual(a.property, b.property) && isValueEqual(a.object, b.object, initialScopes);
202
+ case a.type === AST_NODE_TYPES.ThisExpression && b.type === AST_NODE_TYPES.ThisExpression:
203
+ if (aScope.block === bScope.block) return true;
204
+ return ast.findParentNode(a, ast.isOneOf(thisBlockTypes)) === ast.findParentNode(b, ast.isOneOf(thisBlockTypes));
205
+ default: {
206
+ const aStatic = getStaticValue(a, aScope);
207
+ const bStatic = getStaticValue(b, bScope);
208
+ return aStatic != null && bStatic != null && aStatic.value === bStatic.value;
209
+ }
210
+ }
211
+ }
212
+
213
+ //#endregion
214
+ //#region src/is-assignment-target-equal.ts
215
+ /**
216
+ * Check if two assignment targets are equal
217
+ * Compares nodes directly or by their values
218
+ * @param context The rule context
219
+ * @param a The first node to compare
220
+ * @param b The second node to compare
221
+ * @returns True if the assignment targets are equal
222
+ * @internal
223
+ */
224
+ function isAssignmentTargetEqual(context, a, b) {
225
+ return ast.isNodeEqual(a, b) || isValueEqual(a, b, [context.sourceCode.getScope(a), context.sourceCode.getScope(b)]);
323
226
  }
324
227
 
325
228
  //#endregion
326
- export { findEnclosingAssignmentTarget, findImportSource, findProperty, findVariable, getChildScopes, getObjectType, getVariableDefinitionNode, getVariableDefinitionNodeLoose, getVariables, isAssignmentTargetEqual, isNodeEqual };
229
+ export { findEnclosingAssignmentTarget, findVariable, getObjectType, getVariableInitializer, getVariableInitializerLoose, isAssignmentTargetEqual, isValueEqual };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-react/var",
3
- "version": "3.0.0-next.6",
3
+ "version": "3.0.0-next.60",
4
4
  "description": "ESLint React's TSESTree AST utility module for static analysis of variables.",
5
5
  "homepage": "https://github.com/Rel1cx/eslint-react",
6
6
  "bugs": {
@@ -34,12 +34,12 @@
34
34
  "@typescript-eslint/types": "canary",
35
35
  "@typescript-eslint/utils": "canary",
36
36
  "ts-pattern": "^5.9.0",
37
- "@eslint-react/ast": "3.0.0-next.6",
38
- "@eslint-react/eff": "3.0.0-next.6",
39
- "@eslint-react/shared": "3.0.0-next.6"
37
+ "@eslint-react/eff": "3.0.0-next.60",
38
+ "@eslint-react/ast": "3.0.0-next.60",
39
+ "@eslint-react/shared": "3.0.0-next.60"
40
40
  },
41
41
  "devDependencies": {
42
- "tsdown": "^0.20.3",
42
+ "tsdown": "^0.21.0-beta.2",
43
43
  "@local/configs": "0.0.0"
44
44
  },
45
45
  "peerDependencies": {
@@ -52,6 +52,6 @@
52
52
  "scripts": {
53
53
  "build": "tsdown --dts-resolve",
54
54
  "lint:publish": "publint",
55
- "lint:ts": "tsc --noEmit"
55
+ "lint:ts": "tsl"
56
56
  }
57
57
  }