@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.
- package/dist/index.d.ts +44 -76
- package/dist/index.js +115 -212
- 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/
|
|
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/
|
|
20
|
+
//#region src/find-variable.d.ts
|
|
48
21
|
/**
|
|
49
|
-
* Find
|
|
50
|
-
* @param
|
|
51
|
-
* @
|
|
52
|
-
* @
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
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/
|
|
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/
|
|
73
|
+
//#region src/get-variable-initializer.d.ts
|
|
105
74
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* @param
|
|
109
|
-
* @
|
|
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
|
|
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
|
|
119
|
-
* @param
|
|
120
|
-
* @
|
|
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
|
|
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
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* @
|
|
127
|
-
* @
|
|
128
|
-
* @param
|
|
129
|
-
* @
|
|
130
|
-
* @
|
|
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
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
*
|
|
138
|
-
* @param
|
|
139
|
-
* @
|
|
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
|
|
109
|
+
declare function isValueEqual(a: TSESTree.Node, b: TSESTree.Node, initialScopes: [aScope: Scope, bScope: Scope]): boolean;
|
|
142
110
|
//#endregion
|
|
143
|
-
export { AssignmentTarget, ObjectType, findEnclosingAssignmentTarget,
|
|
111
|
+
export { AssignmentTarget, ObjectType, findEnclosingAssignmentTarget, findVariable, getObjectType, getVariableInitializer, getVariableInitializerLoose, isAssignmentTargetEqual, isValueEqual };
|
package/dist/index.js
CHANGED
|
@@ -1,61 +1,30 @@
|
|
|
1
|
-
import
|
|
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
|
|
7
|
-
import {
|
|
5
|
+
import * as ast from "@eslint-react/ast";
|
|
6
|
+
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
8
7
|
|
|
9
|
-
//#region src/
|
|
8
|
+
//#region src/find-enclosing-assignment-target.ts
|
|
10
9
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
14
|
-
* @
|
|
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
|
|
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
|
|
22
|
-
case
|
|
23
|
-
case
|
|
24
|
-
|
|
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/
|
|
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/
|
|
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
|
-
*
|
|
93
|
-
* @param
|
|
94
|
-
* @param
|
|
95
|
-
* @
|
|
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
|
|
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.
|
|
162
|
-
case node.type === AST_NODE_TYPES.
|
|
163
|
-
case node.
|
|
164
|
-
|
|
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
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* @param
|
|
172
|
-
* @
|
|
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
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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/
|
|
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(
|
|
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/
|
|
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
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* @param
|
|
300
|
-
* @param
|
|
301
|
-
* @
|
|
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
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
|
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
|
|
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,
|
|
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.
|
|
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/
|
|
38
|
-
"@eslint-react/
|
|
39
|
-
"@eslint-react/shared": "3.0.0-next.
|
|
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.
|
|
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": "
|
|
55
|
+
"lint:ts": "tsl"
|
|
56
56
|
}
|
|
57
57
|
}
|