@eslint-react/var 2.0.0-next.6 → 2.0.0-next.61
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 +77 -73
- package/dist/index.js +251 -240
- package/package.json +9 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,50 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Get all variables from the given scope up to the global scope
|
|
7
|
-
* @param initialScope The scope to start from
|
|
8
|
-
* @returns All variables from the given scope up to the global scope
|
|
9
|
-
*/
|
|
10
|
-
declare function getVariables(initialScope: Scope): Variable[];
|
|
11
|
-
declare const findVariable: {
|
|
12
|
-
(initialScope: Scope): (nameOrNode: string | TSESTree.Identifier | _) => Variable | _;
|
|
13
|
-
(nameOrNode: string | TSESTree.Identifier | _, initialScope: Scope): Variable | _;
|
|
14
|
-
};
|
|
15
|
-
declare function findPropertyInProperties(name: string, properties: (TSESTree.Property | TSESTree.RestElement | TSESTree.SpreadElement)[], initialScope: Scope, seen?: Set<string>): (typeof properties)[number] | _;
|
|
1
|
+
import { TSESTree } from "@typescript-eslint/types";
|
|
2
|
+
import { unit } from "@eslint-react/eff";
|
|
3
|
+
import { Scope, Variable } from "@typescript-eslint/scope-manager";
|
|
16
4
|
|
|
5
|
+
//#region src/misc.d.ts
|
|
6
|
+
declare function getChildScopes(scope: Scope): readonly Scope[];
|
|
7
|
+
declare function findProperty(name: string, properties: (TSESTree.Property | TSESTree.RestElement | TSESTree.SpreadElement)[], initialScope: Scope, seen?: Set<string>): (typeof properties)[number] | unit;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/value-construction.d.ts
|
|
17
10
|
declare const ConstructionDetectionHint: {
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
None: bigint;
|
|
12
|
+
StrictCallExpression: bigint;
|
|
20
13
|
};
|
|
21
14
|
type Construction = {
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
kind: "ArrayExpression";
|
|
16
|
+
node: TSESTree.ArrayExpression;
|
|
24
17
|
} | {
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
kind: "CallExpression";
|
|
19
|
+
node: TSESTree.CallExpression;
|
|
27
20
|
} | {
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
kind: "ClassExpression";
|
|
22
|
+
node: TSESTree.ClassExpression;
|
|
30
23
|
} | {
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
kind: "FunctionDeclaration";
|
|
25
|
+
node: TSESTree.FunctionDeclaration;
|
|
33
26
|
} | {
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
kind: "FunctionExpression";
|
|
28
|
+
node: TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression;
|
|
36
29
|
} | {
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
kind: "JSXElement";
|
|
31
|
+
node: TSESTree.JSXElement | TSESTree.JSXFragment;
|
|
39
32
|
} | {
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
kind: "NewExpression";
|
|
34
|
+
node: TSESTree.NewExpression;
|
|
42
35
|
} | {
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
kind: "ObjectExpression";
|
|
37
|
+
node: TSESTree.ObjectExpression;
|
|
45
38
|
} | {
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
kind: "RegExpLiteral";
|
|
40
|
+
node: TSESTree.RegExpLiteral;
|
|
48
41
|
};
|
|
49
42
|
/**
|
|
50
43
|
* Detects the construction type of a given node.
|
|
@@ -53,50 +46,61 @@ type Construction = {
|
|
|
53
46
|
* @param hint Optional hint to control the detection behavior.
|
|
54
47
|
* @returns The construction type of the node, or `_` if not found.
|
|
55
48
|
*/
|
|
56
|
-
declare function getConstruction(node: TSESTree.Node |
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
declare function getConstruction(node: TSESTree.Node | unit, initialScope: Scope, hint?: bigint): Construction | unit;
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/value-equal.d.ts
|
|
52
|
+
/**
|
|
53
|
+
* Determines whether node value equals to another node value
|
|
54
|
+
* @param a node to compare
|
|
55
|
+
* @param b node to compare
|
|
56
|
+
* @param initialScopes initial scopes of the two nodes
|
|
57
|
+
* @returns `true` if node value equal
|
|
58
|
+
*/
|
|
59
|
+
declare function isNodeValueEqual(a: TSESTree.Node, b: TSESTree.Node, initialScopes: [aScope: Scope, bScope: Scope]): boolean;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/value-helper.d.ts
|
|
64
62
|
type LazyValue = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
kind: "lazy";
|
|
64
|
+
node: TSESTree.Node;
|
|
65
|
+
initialScope: Scope | unit;
|
|
68
66
|
} | {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
kind: "none";
|
|
68
|
+
node: TSESTree.Node;
|
|
69
|
+
initialScope: Scope | unit;
|
|
72
70
|
} | {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
kind: "some";
|
|
72
|
+
node: TSESTree.Node;
|
|
73
|
+
value: unknown;
|
|
74
|
+
initialScope: Scope | unit;
|
|
77
75
|
};
|
|
78
76
|
declare function toStaticValue(lazyValue: LazyValue): {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
readonly kind: "none";
|
|
78
|
+
readonly node: TSESTree.Node;
|
|
79
|
+
readonly initialScope: Scope | undefined;
|
|
80
|
+
readonly value?: never;
|
|
83
81
|
} | {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
readonly kind: "some";
|
|
83
|
+
readonly node: TSESTree.Node;
|
|
84
|
+
readonly initialScope: Scope | undefined;
|
|
85
|
+
readonly value: unknown;
|
|
88
86
|
};
|
|
89
|
-
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/variable-assignment.d.ts
|
|
89
|
+
declare function findAssignmentTarget(node: TSESTree.Node | unit, prev?: TSESTree.Node): TSESTree.BindingName | TSESTree.Expression | unit;
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/variable-extractor.d.ts
|
|
90
92
|
/**
|
|
91
|
-
*
|
|
92
|
-
* @param
|
|
93
|
-
* @
|
|
94
|
-
* @param initialScopes initial scopes of the two nodes
|
|
95
|
-
* @returns `true` if node value equal
|
|
93
|
+
* Get all variables from the given scope up to the global scope
|
|
94
|
+
* @param initialScope The scope to start from
|
|
95
|
+
* @returns All variables from the given scope up to the global scope
|
|
96
96
|
*/
|
|
97
|
-
declare function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
declare function getVariables(initialScope: Scope): Variable[];
|
|
98
|
+
declare const findVariable: {
|
|
99
|
+
(initialScope: Scope): (nameOrNode: string | TSESTree.Identifier | unit) => Variable | unit;
|
|
100
|
+
(nameOrNode: string | TSESTree.Identifier | unit, initialScope: Scope): Variable | unit;
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/variable-resolver.d.ts
|
|
104
|
+
declare function getVariableDefinitionNode(variable: Variable | unit, at: number): unit | TSESTree.ClassDeclaration | TSESTree.ClassDeclarationWithName | TSESTree.ClassDeclarationWithOptionalName | TSESTree.Expression | TSESTree.FunctionDeclaration | TSESTree.FunctionDeclarationWithName | TSESTree.FunctionDeclarationWithOptionalName;
|
|
105
|
+
//#endregion
|
|
106
|
+
export { Construction, ConstructionDetectionHint, LazyValue, findAssignmentTarget, findProperty, findVariable, getChildScopes, getConstruction, getVariableDefinitionNode, getVariables, isNodeValueEqual, toStaticValue };
|
package/dist/index.js
CHANGED
|
@@ -1,256 +1,267 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import * as ASTUtils from
|
|
5
|
-
import { getStaticValue } from
|
|
6
|
-
import * as AST from
|
|
1
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
2
|
+
import { dual, unit } from "@eslint-react/eff";
|
|
3
|
+
import { DefinitionType, ScopeType } from "@typescript-eslint/scope-manager";
|
|
4
|
+
import * as ASTUtils from "@typescript-eslint/utils/ast-utils";
|
|
5
|
+
import { getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
6
|
+
import * as AST from "@eslint-react/ast";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
case (def.type === DefinitionType.FunctionName && def.node.type === AST_NODE_TYPES.FunctionDeclaration):
|
|
15
|
-
return def.node;
|
|
16
|
-
case (def.type === DefinitionType.ClassName && def.node.type === AST_NODE_TYPES.ClassDeclaration):
|
|
17
|
-
return def.node;
|
|
18
|
-
case ("init" in def.node && def.node.init != null && !("declarations" in def.node.init)):
|
|
19
|
-
return def.node.init;
|
|
20
|
-
default:
|
|
21
|
-
return _;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// src/var-collect.ts
|
|
8
|
+
//#region src/variable-extractor.ts
|
|
9
|
+
/**
|
|
10
|
+
* Get all variables from the given scope up to the global scope
|
|
11
|
+
* @param initialScope The scope to start from
|
|
12
|
+
* @returns All variables from the given scope up to the global scope
|
|
13
|
+
*/
|
|
26
14
|
function getVariables(initialScope) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
let scope = initialScope;
|
|
16
|
+
const variables = [...scope.variables];
|
|
17
|
+
while (scope.type !== ScopeType.global) {
|
|
18
|
+
scope = scope.upper;
|
|
19
|
+
variables.push(...scope.variables);
|
|
20
|
+
}
|
|
21
|
+
return variables.reverse();
|
|
34
22
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
const findVariable = dual(2, (nameOrNode, initialScope) => {
|
|
24
|
+
if (nameOrNode == null) return unit;
|
|
25
|
+
return ASTUtils.findVariable(initialScope, nameOrNode) ?? unit;
|
|
38
26
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return findPropertyInProperties(
|
|
53
|
-
name,
|
|
54
|
-
variableNode.properties,
|
|
55
|
-
initialScope,
|
|
56
|
-
seen
|
|
57
|
-
) != null;
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
case AST_NODE_TYPES.ObjectExpression: {
|
|
62
|
-
return findPropertyInProperties(
|
|
63
|
-
name,
|
|
64
|
-
prop.argument.properties,
|
|
65
|
-
initialScope,
|
|
66
|
-
seen
|
|
67
|
-
) != null;
|
|
68
|
-
}
|
|
69
|
-
default:
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
74
|
-
});
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/variable-resolver.ts
|
|
30
|
+
function getVariableDefinitionNode(variable, at) {
|
|
31
|
+
if (variable == null) return unit;
|
|
32
|
+
const def = variable.defs.at(at);
|
|
33
|
+
if (def == null) return unit;
|
|
34
|
+
switch (true) {
|
|
35
|
+
case def.type === DefinitionType.FunctionName && def.node.type === AST_NODE_TYPES.FunctionDeclaration: return def.node;
|
|
36
|
+
case def.type === DefinitionType.ClassName && def.node.type === AST_NODE_TYPES.ClassDeclaration: return def.node;
|
|
37
|
+
case "init" in def.node && def.node.init != null && !("declarations" in def.node.init): return def.node.init;
|
|
38
|
+
default: return unit;
|
|
39
|
+
}
|
|
75
40
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
case AST_NODE_TYPES.JSXElement:
|
|
84
|
-
case AST_NODE_TYPES.JSXFragment:
|
|
85
|
-
return { kind: "JSXElement", node };
|
|
86
|
-
case AST_NODE_TYPES.ArrayExpression:
|
|
87
|
-
return { kind: "ArrayExpression", node };
|
|
88
|
-
case AST_NODE_TYPES.ObjectExpression:
|
|
89
|
-
return { kind: "ObjectExpression", node };
|
|
90
|
-
case AST_NODE_TYPES.ClassExpression:
|
|
91
|
-
return { kind: "ClassExpression", node };
|
|
92
|
-
case AST_NODE_TYPES.NewExpression:
|
|
93
|
-
return { kind: "NewExpression", node };
|
|
94
|
-
case AST_NODE_TYPES.FunctionExpression:
|
|
95
|
-
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
96
|
-
return { kind: "FunctionExpression", node };
|
|
97
|
-
case AST_NODE_TYPES.CallExpression: {
|
|
98
|
-
if (hint & ConstructionDetectionHint.StrictCallExpression) {
|
|
99
|
-
return { kind: "CallExpression", node };
|
|
100
|
-
}
|
|
101
|
-
return _;
|
|
102
|
-
}
|
|
103
|
-
case AST_NODE_TYPES.MemberExpression: {
|
|
104
|
-
if (!("object" in node)) return _;
|
|
105
|
-
return getConstruction(node.object, initialScope, hint);
|
|
106
|
-
}
|
|
107
|
-
case AST_NODE_TYPES.AssignmentExpression:
|
|
108
|
-
case AST_NODE_TYPES.AssignmentPattern: {
|
|
109
|
-
if (!("right" in node)) return _;
|
|
110
|
-
return getConstruction(node.right, initialScope, hint);
|
|
111
|
-
}
|
|
112
|
-
case AST_NODE_TYPES.LogicalExpression: {
|
|
113
|
-
const lvc = getConstruction(node.left, initialScope, hint);
|
|
114
|
-
if (lvc == null) return _;
|
|
115
|
-
return getConstruction(node.right, initialScope, hint);
|
|
116
|
-
}
|
|
117
|
-
case AST_NODE_TYPES.ConditionalExpression: {
|
|
118
|
-
const cvc = getConstruction(node.consequent, initialScope, hint);
|
|
119
|
-
if (cvc == null) return _;
|
|
120
|
-
return getConstruction(node.alternate, initialScope, hint);
|
|
121
|
-
}
|
|
122
|
-
case AST_NODE_TYPES.Identifier: {
|
|
123
|
-
if (!("name" in node) || typeof node.name !== "string") {
|
|
124
|
-
return _;
|
|
125
|
-
}
|
|
126
|
-
const variable = initialScope.set.get(node.name);
|
|
127
|
-
const variableNode = getVariableInitNode(variable, -1);
|
|
128
|
-
return getConstruction(variableNode, initialScope, hint);
|
|
129
|
-
}
|
|
130
|
-
case AST_NODE_TYPES.Literal: {
|
|
131
|
-
if ("regex" in node) {
|
|
132
|
-
return { kind: "RegExpLiteral", node };
|
|
133
|
-
}
|
|
134
|
-
return _;
|
|
135
|
-
}
|
|
136
|
-
default: {
|
|
137
|
-
if (!("expression" in node) || typeof node.expression !== "object") {
|
|
138
|
-
return _;
|
|
139
|
-
}
|
|
140
|
-
return getConstruction(node.expression, initialScope, hint);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/misc.ts
|
|
44
|
+
function getChildScopes(scope) {
|
|
45
|
+
const scopes = [scope];
|
|
46
|
+
for (const childScope of scope.childScopes) scopes.push(...getChildScopes(childScope));
|
|
47
|
+
return scopes;
|
|
143
48
|
}
|
|
144
|
-
function
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
49
|
+
function findProperty(name, properties, initialScope, seen = /* @__PURE__ */ new Set()) {
|
|
50
|
+
return properties.findLast((prop) => {
|
|
51
|
+
if (prop.type === AST_NODE_TYPES.Property) return "name" in prop.key && prop.key.name === name;
|
|
52
|
+
if (prop.type === AST_NODE_TYPES.SpreadElement) switch (prop.argument.type) {
|
|
53
|
+
case AST_NODE_TYPES.Identifier: {
|
|
54
|
+
if (seen.has(prop.argument.name)) return false;
|
|
55
|
+
const variable = findVariable(prop.argument.name, initialScope);
|
|
56
|
+
const variableNode = getVariableDefinitionNode(variable, 0);
|
|
57
|
+
if (variableNode?.type === AST_NODE_TYPES.ObjectExpression) {
|
|
58
|
+
seen.add(prop.argument.name);
|
|
59
|
+
return findProperty(name, variableNode.properties, initialScope, seen) != null;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
case AST_NODE_TYPES.ObjectExpression: return findProperty(name, prop.argument.properties, initialScope, seen) != null;
|
|
64
|
+
default: return false;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
});
|
|
156
68
|
}
|
|
157
69
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/value-construction.ts
|
|
72
|
+
const ConstructionDetectionHint = {
|
|
73
|
+
None: 0n,
|
|
74
|
+
StrictCallExpression: 1n << 0n
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Detects the construction type of a given node.
|
|
78
|
+
* @param node The node to check.
|
|
79
|
+
* @param initialScope The initial scope to check for variable declarations.
|
|
80
|
+
* @param hint Optional hint to control the detection behavior.
|
|
81
|
+
* @returns The construction type of the node, or `_` if not found.
|
|
82
|
+
*/
|
|
83
|
+
function getConstruction(node, initialScope, hint = ConstructionDetectionHint.None) {
|
|
84
|
+
if (node == null) return unit;
|
|
85
|
+
switch (node.type) {
|
|
86
|
+
case AST_NODE_TYPES.JSXElement:
|
|
87
|
+
case AST_NODE_TYPES.JSXFragment: return {
|
|
88
|
+
kind: "JSXElement",
|
|
89
|
+
node
|
|
90
|
+
};
|
|
91
|
+
case AST_NODE_TYPES.ArrayExpression: return {
|
|
92
|
+
kind: "ArrayExpression",
|
|
93
|
+
node
|
|
94
|
+
};
|
|
95
|
+
case AST_NODE_TYPES.ObjectExpression: return {
|
|
96
|
+
kind: "ObjectExpression",
|
|
97
|
+
node
|
|
98
|
+
};
|
|
99
|
+
case AST_NODE_TYPES.ClassExpression: return {
|
|
100
|
+
kind: "ClassExpression",
|
|
101
|
+
node
|
|
102
|
+
};
|
|
103
|
+
case AST_NODE_TYPES.NewExpression: return {
|
|
104
|
+
kind: "NewExpression",
|
|
105
|
+
node
|
|
106
|
+
};
|
|
107
|
+
case AST_NODE_TYPES.FunctionExpression:
|
|
108
|
+
case AST_NODE_TYPES.ArrowFunctionExpression: return {
|
|
109
|
+
kind: "FunctionExpression",
|
|
110
|
+
node
|
|
111
|
+
};
|
|
112
|
+
case AST_NODE_TYPES.CallExpression:
|
|
113
|
+
if (hint & ConstructionDetectionHint.StrictCallExpression) return {
|
|
114
|
+
kind: "CallExpression",
|
|
115
|
+
node
|
|
116
|
+
};
|
|
117
|
+
return unit;
|
|
118
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
119
|
+
if (!("object" in node)) return unit;
|
|
120
|
+
return getConstruction(node.object, initialScope, hint);
|
|
121
|
+
case AST_NODE_TYPES.AssignmentExpression:
|
|
122
|
+
case AST_NODE_TYPES.AssignmentPattern:
|
|
123
|
+
if (!("right" in node)) return unit;
|
|
124
|
+
return getConstruction(node.right, initialScope, hint);
|
|
125
|
+
case AST_NODE_TYPES.LogicalExpression: {
|
|
126
|
+
const lvc = getConstruction(node.left, initialScope, hint);
|
|
127
|
+
if (lvc == null) return unit;
|
|
128
|
+
return getConstruction(node.right, initialScope, hint);
|
|
129
|
+
}
|
|
130
|
+
case AST_NODE_TYPES.ConditionalExpression: {
|
|
131
|
+
const cvc = getConstruction(node.consequent, initialScope, hint);
|
|
132
|
+
if (cvc == null) return unit;
|
|
133
|
+
return getConstruction(node.alternate, initialScope, hint);
|
|
134
|
+
}
|
|
135
|
+
case AST_NODE_TYPES.Identifier: {
|
|
136
|
+
if (!("name" in node) || typeof node.name !== "string") return unit;
|
|
137
|
+
const variable = initialScope.set.get(node.name);
|
|
138
|
+
const variableNode = getVariableDefinitionNode(variable, -1);
|
|
139
|
+
return getConstruction(variableNode, initialScope, hint);
|
|
140
|
+
}
|
|
141
|
+
case AST_NODE_TYPES.Literal:
|
|
142
|
+
if ("regex" in node) return {
|
|
143
|
+
kind: "RegExpLiteral",
|
|
144
|
+
node
|
|
145
|
+
};
|
|
146
|
+
return unit;
|
|
147
|
+
default:
|
|
148
|
+
if (!("expression" in node) || typeof node.expression !== "object") return unit;
|
|
149
|
+
return getConstruction(node.expression, initialScope, hint);
|
|
150
|
+
}
|
|
165
151
|
}
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/value-helper.ts
|
|
166
155
|
function toStaticValue(lazyValue) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
156
|
+
const { kind, node, initialScope } = lazyValue;
|
|
157
|
+
if (kind !== "lazy") return lazyValue;
|
|
158
|
+
const staticValue = initialScope == null ? getStaticValue(node) : getStaticValue(node, initialScope);
|
|
159
|
+
return staticValue == null ? {
|
|
160
|
+
kind: "none",
|
|
161
|
+
node,
|
|
162
|
+
initialScope
|
|
163
|
+
} : {
|
|
164
|
+
kind: "some",
|
|
165
|
+
node,
|
|
166
|
+
initialScope,
|
|
167
|
+
value: staticValue.value
|
|
168
|
+
};
|
|
173
169
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
170
|
+
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/value-equal.ts
|
|
173
|
+
const thisBlockTypes = [
|
|
174
|
+
AST_NODE_TYPES.FunctionDeclaration,
|
|
175
|
+
AST_NODE_TYPES.FunctionExpression,
|
|
176
|
+
AST_NODE_TYPES.ClassBody,
|
|
177
|
+
AST_NODE_TYPES.Program
|
|
179
178
|
];
|
|
179
|
+
/**
|
|
180
|
+
* Determines whether node value equals to another node value
|
|
181
|
+
* @param a node to compare
|
|
182
|
+
* @param b node to compare
|
|
183
|
+
* @param initialScopes initial scopes of the two nodes
|
|
184
|
+
* @returns `true` if node value equal
|
|
185
|
+
*/
|
|
180
186
|
function isNodeValueEqual(a, b, initialScopes) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
187
|
+
const [aScope, bScope] = initialScopes;
|
|
188
|
+
switch (true) {
|
|
189
|
+
case a === b: return true;
|
|
190
|
+
case a.type === AST_NODE_TYPES.Literal && b.type === AST_NODE_TYPES.Literal: return a.value === b.value;
|
|
191
|
+
case a.type === AST_NODE_TYPES.TemplateElement && b.type === AST_NODE_TYPES.TemplateElement: return a.value.cooked === b.value.cooked;
|
|
192
|
+
case a.type === AST_NODE_TYPES.Identifier && b.type === AST_NODE_TYPES.Identifier: {
|
|
193
|
+
const aVar = findVariable(a, aScope);
|
|
194
|
+
const bVar = findVariable(b, bScope);
|
|
195
|
+
const aVarNode = getVariableDefinitionNodeLoose(aVar, 0);
|
|
196
|
+
const bVarNode = getVariableDefinitionNodeLoose(bVar, 0);
|
|
197
|
+
const aVarNodeParent = aVarNode?.parent;
|
|
198
|
+
const bVarNodeParent = bVarNode?.parent;
|
|
199
|
+
const aDef = aVar?.defs.at(0);
|
|
200
|
+
const bDef = bVar?.defs.at(0);
|
|
201
|
+
const aDefParentParent = aDef?.parent?.parent;
|
|
202
|
+
const bDefParentParent = bDef?.parent?.parent;
|
|
203
|
+
switch (true) {
|
|
204
|
+
case aVarNodeParent?.type === AST_NODE_TYPES.CallExpression && bVarNodeParent?.type === AST_NODE_TYPES.CallExpression && AST.isFunction(aVarNode) && AST.isFunction(bVarNode): {
|
|
205
|
+
if (!AST.isNodeEqual(aVarNodeParent.callee, bVarNodeParent.callee)) return false;
|
|
206
|
+
const aParams = aVarNode.params;
|
|
207
|
+
const bParams = bVarNode.params;
|
|
208
|
+
const aPos = aParams.findIndex((x) => AST.isNodeEqual(x, a));
|
|
209
|
+
const bPos = bParams.findIndex((x) => AST.isNodeEqual(x, b));
|
|
210
|
+
return aPos !== -1 && bPos !== -1 && aPos === bPos;
|
|
211
|
+
}
|
|
212
|
+
case aDefParentParent?.type === AST_NODE_TYPES.ForOfStatement && bDefParentParent?.type === AST_NODE_TYPES.ForOfStatement: {
|
|
213
|
+
const aLeft = aDefParentParent.left;
|
|
214
|
+
const bLeft = bDefParentParent.left;
|
|
215
|
+
if (aLeft.type !== bLeft.type) return false;
|
|
216
|
+
const aRight = aDefParentParent.right;
|
|
217
|
+
const bRight = bDefParentParent.right;
|
|
218
|
+
return AST.isNodeEqual(aRight, bRight);
|
|
219
|
+
}
|
|
220
|
+
default: return aVar != null && bVar != null && aVar === bVar;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
case a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression: return AST.isNodeEqual(a.property, b.property) && isNodeValueEqual(a.object, b.object, initialScopes);
|
|
224
|
+
case a.type === AST_NODE_TYPES.ThisExpression && b.type === AST_NODE_TYPES.ThisExpression: {
|
|
225
|
+
if (aScope.block === bScope.block) return true;
|
|
226
|
+
const aFunction = AST.findParentNode(a, AST.isOneOf(thisBlockTypes));
|
|
227
|
+
const bFunction = AST.findParentNode(b, AST.isOneOf(thisBlockTypes));
|
|
228
|
+
return aFunction === bFunction;
|
|
229
|
+
}
|
|
230
|
+
default: {
|
|
231
|
+
const aStatic = toStaticValue({
|
|
232
|
+
kind: "lazy",
|
|
233
|
+
node: a,
|
|
234
|
+
initialScope: aScope
|
|
235
|
+
});
|
|
236
|
+
const bStatic = toStaticValue({
|
|
237
|
+
kind: "lazy",
|
|
238
|
+
node: b,
|
|
239
|
+
initialScope: bScope
|
|
240
|
+
});
|
|
241
|
+
return aStatic.kind !== "none" && bStatic.kind !== "none" && aStatic.value === bStatic.value;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function getVariableDefinitionNodeLoose(variable, at) {
|
|
246
|
+
if (variable == null) return unit;
|
|
247
|
+
const node = getVariableDefinitionNode(variable, at);
|
|
248
|
+
if (node != null) return node;
|
|
249
|
+
const def = variable.defs.at(at);
|
|
250
|
+
if (def?.type === DefinitionType.Parameter && AST.isFunction(def.node)) return def.node;
|
|
251
|
+
return unit;
|
|
246
252
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
253
|
+
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/variable-assignment.ts
|
|
256
|
+
function findAssignmentTarget(node, prev) {
|
|
257
|
+
if (node == null) return unit;
|
|
258
|
+
switch (true) {
|
|
259
|
+
case node.type === AST_NODE_TYPES.VariableDeclarator && node.init === prev: return node.id;
|
|
260
|
+
case node.type === AST_NODE_TYPES.AssignmentExpression && node.right === prev: return node.left;
|
|
261
|
+
case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return unit;
|
|
262
|
+
default: return findAssignmentTarget(node.parent, node);
|
|
263
|
+
}
|
|
254
264
|
}
|
|
255
265
|
|
|
256
|
-
|
|
266
|
+
//#endregion
|
|
267
|
+
export { ConstructionDetectionHint, findAssignmentTarget, findProperty, findVariable, getChildScopes, getConstruction, getVariableDefinitionNode, getVariables, isNodeValueEqual, toStaticValue };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/var",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.61",
|
|
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": {
|
|
@@ -27,24 +27,23 @@
|
|
|
27
27
|
"./package.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
31
|
-
"@typescript-eslint/types": "^8.
|
|
32
|
-
"@typescript-eslint/utils": "^8.
|
|
30
|
+
"@typescript-eslint/scope-manager": "^8.41.0",
|
|
31
|
+
"@typescript-eslint/types": "^8.41.0",
|
|
32
|
+
"@typescript-eslint/utils": "^8.41.0",
|
|
33
33
|
"string-ts": "^2.2.1",
|
|
34
|
-
"ts-pattern": "^5.
|
|
35
|
-
"@eslint-react/ast": "2.0.0-next.
|
|
36
|
-
"@eslint-react/eff": "2.0.0-next.
|
|
34
|
+
"ts-pattern": "^5.8.0",
|
|
35
|
+
"@eslint-react/ast": "2.0.0-next.61",
|
|
36
|
+
"@eslint-react/eff": "2.0.0-next.61"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"
|
|
39
|
+
"tsdown": "^0.14.2",
|
|
40
40
|
"@local/configs": "0.0.0"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
|
-
"bun": ">=1.0.15",
|
|
44
43
|
"node": ">=20.19.0"
|
|
45
44
|
},
|
|
46
45
|
"scripts": {
|
|
47
|
-
"build": "
|
|
46
|
+
"build": "tsdown --dts-resolve",
|
|
48
47
|
"lint:publish": "publint",
|
|
49
48
|
"lint:ts": "tsc --noEmit"
|
|
50
49
|
}
|