@eslint-react/var 3.0.0-next.63 → 3.0.0-next.64
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 +36 -6
- package/dist/index.js +80 -32
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unit } from "@eslint-react/eff";
|
|
2
1
|
import { Scope } from "@typescript-eslint/scope-manager";
|
|
3
2
|
import { TSESTree } from "@typescript-eslint/types";
|
|
4
3
|
import { RuleContext } from "@eslint-react/shared";
|
|
@@ -36,10 +35,9 @@ type ObjectType = {
|
|
|
36
35
|
/**
|
|
37
36
|
* Detect the ObjectType of a given node
|
|
38
37
|
* @param node The node to check
|
|
39
|
-
* @param initialScope The initial scope to check for variable declarations
|
|
40
38
|
* @returns The ObjectType of the node, or undefined if not detected
|
|
41
39
|
*/
|
|
42
|
-
declare function computeObjectType(node: TSESTree.Node |
|
|
40
|
+
declare function computeObjectType(context: RuleContext, node: TSESTree.Node | null): ObjectType | null;
|
|
43
41
|
//#endregion
|
|
44
42
|
//#region src/find-enclosing-assignment-target.d.ts
|
|
45
43
|
/**
|
|
@@ -47,9 +45,9 @@ declare function computeObjectType(node: TSESTree.Node | unit, initialScope: Sco
|
|
|
47
45
|
*
|
|
48
46
|
* @todo Verify correctness and completeness of this function
|
|
49
47
|
* @param node The starting node
|
|
50
|
-
* @returns The enclosing assignment target node, or
|
|
48
|
+
* @returns The enclosing assignment target node, or null if not found
|
|
51
49
|
*/
|
|
52
|
-
declare function findEnclosingAssignmentTarget(node: TSESTree.Node): TSESTree.ArrayExpression | TSESTree.ArrayPattern | TSESTree.ArrowFunctionExpression | TSESTree.AssignmentExpression | TSESTree.AwaitExpression | TSESTree.PrivateInExpression | TSESTree.SymmetricBinaryExpression | TSESTree.CallExpression | TSESTree.ChainExpression | TSESTree.ClassExpression | TSESTree.ConditionalExpression | TSESTree.FunctionExpression | TSESTree.Identifier | TSESTree.ImportExpression | TSESTree.JSXElement | TSESTree.JSXFragment | TSESTree.BigIntLiteral | TSESTree.BooleanLiteral | TSESTree.NullLiteral | TSESTree.NumberLiteral | TSESTree.RegExpLiteral | TSESTree.StringLiteral | TSESTree.LogicalExpression | TSESTree.MemberExpressionComputedName | TSESTree.MemberExpressionNonComputedName | TSESTree.MetaProperty | TSESTree.NewExpression | TSESTree.ObjectExpression | TSESTree.ObjectPattern | TSESTree.PrivateIdentifier | TSESTree.SequenceExpression | TSESTree.Super | TSESTree.TaggedTemplateExpression | TSESTree.TemplateLiteral | TSESTree.ThisExpression | TSESTree.TSAsExpression | TSESTree.TSInstantiationExpression | TSESTree.TSNonNullExpression | TSESTree.TSSatisfiesExpression | TSESTree.TSTypeAssertion | TSESTree.UnaryExpressionBitwiseNot | TSESTree.UnaryExpressionDelete | TSESTree.UnaryExpressionMinus | TSESTree.UnaryExpressionNot | TSESTree.UnaryExpressionPlus | TSESTree.UnaryExpressionTypeof | TSESTree.UnaryExpressionVoid | TSESTree.UpdateExpression | TSESTree.YieldExpression |
|
|
50
|
+
declare function findEnclosingAssignmentTarget(node: TSESTree.Node): TSESTree.ArrayExpression | TSESTree.ArrayPattern | TSESTree.ArrowFunctionExpression | TSESTree.AssignmentExpression | TSESTree.AwaitExpression | TSESTree.PrivateInExpression | TSESTree.SymmetricBinaryExpression | TSESTree.CallExpression | TSESTree.ChainExpression | TSESTree.ClassExpression | TSESTree.ConditionalExpression | TSESTree.FunctionExpression | TSESTree.Identifier | TSESTree.ImportExpression | TSESTree.JSXElement | TSESTree.JSXFragment | TSESTree.BigIntLiteral | TSESTree.BooleanLiteral | TSESTree.NullLiteral | TSESTree.NumberLiteral | TSESTree.RegExpLiteral | TSESTree.StringLiteral | TSESTree.LogicalExpression | TSESTree.MemberExpressionComputedName | TSESTree.MemberExpressionNonComputedName | TSESTree.MetaProperty | TSESTree.NewExpression | TSESTree.ObjectExpression | TSESTree.ObjectPattern | TSESTree.PrivateIdentifier | TSESTree.SequenceExpression | TSESTree.Super | TSESTree.TaggedTemplateExpression | TSESTree.TemplateLiteral | TSESTree.ThisExpression | TSESTree.TSAsExpression | TSESTree.TSInstantiationExpression | TSESTree.TSNonNullExpression | TSESTree.TSSatisfiesExpression | TSESTree.TSTypeAssertion | TSESTree.UnaryExpressionBitwiseNot | TSESTree.UnaryExpressionDelete | TSESTree.UnaryExpressionMinus | TSESTree.UnaryExpressionNot | TSESTree.UnaryExpressionPlus | TSESTree.UnaryExpressionTypeof | TSESTree.UnaryExpressionVoid | TSESTree.UpdateExpression | TSESTree.YieldExpression | null;
|
|
53
51
|
/**
|
|
54
52
|
* Type representing the possible assignment targets returned by `findEnclosingAssignmentTarget`
|
|
55
53
|
*/
|
|
@@ -77,4 +75,36 @@ declare function isAssignmentTargetEqual(context: RuleContext, a: TSESTree.Node,
|
|
|
77
75
|
*/
|
|
78
76
|
declare function isValueEqual(a: TSESTree.Node, b: TSESTree.Node, initialScopes: [aScope: Scope, bScope: Scope]): boolean;
|
|
79
77
|
//#endregion
|
|
80
|
-
|
|
78
|
+
//#region src/resolve.d.ts
|
|
79
|
+
/**
|
|
80
|
+
* Resolves an identifier to the AST node that represents its value,
|
|
81
|
+
* suitable for use in ESLint rule analysis.
|
|
82
|
+
*
|
|
83
|
+
* The resolution follows these rules per definition type:
|
|
84
|
+
*
|
|
85
|
+
* | Definition type | `def.node` | Returns |
|
|
86
|
+
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
87
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` (or `null`) |
|
|
88
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
89
|
+
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
90
|
+
* | `Parameter` | containing function node | `def.node` (if a real function) |
|
|
91
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
92
|
+
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
93
|
+
* | `ImportBinding` | import specifier | `null` |
|
|
94
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
95
|
+
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
96
|
+
* | `Type` | type alias node | `null` |
|
|
97
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
98
|
+
*
|
|
99
|
+
* @param context The ESLint rule context used for scope lookup.
|
|
100
|
+
* @param node The identifier to resolve.
|
|
101
|
+
* @param at Which definition to use when multiple exist (default: `0`; pass `-1` for the last).
|
|
102
|
+
* @param localOnly When `true`, look up the variable only in the node's own scope (faster, but
|
|
103
|
+
* will miss variables declared in an outer scope). When `false` (default), traverse the scope
|
|
104
|
+
* chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
105
|
+
* correctly.
|
|
106
|
+
* @returns The resolved node, or `null` if the identifier cannot be resolved to a value node.
|
|
107
|
+
*/
|
|
108
|
+
declare function resolve(context: RuleContext, node: TSESTree.Identifier, at?: number, localOnly?: boolean): TSESTree.Node | null;
|
|
109
|
+
//#endregion
|
|
110
|
+
export { AssignmentTarget, ObjectType, computeObjectType, findEnclosingAssignmentTarget, isAssignmentTargetEqual, isValueEqual, resolve };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,74 @@
|
|
|
1
|
-
import { unit } from "@eslint-react/eff";
|
|
2
1
|
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
3
2
|
import { AST_NODE_TYPES } from "@typescript-eslint/types";
|
|
4
3
|
import * as ast from "@eslint-react/ast";
|
|
5
4
|
import { findVariable, getStaticValue } from "@typescript-eslint/utils/ast-utils";
|
|
6
5
|
|
|
6
|
+
//#region src/resolve.ts
|
|
7
|
+
/**
|
|
8
|
+
* Resolves an identifier to the AST node that represents its value,
|
|
9
|
+
* suitable for use in ESLint rule analysis.
|
|
10
|
+
*
|
|
11
|
+
* The resolution follows these rules per definition type:
|
|
12
|
+
*
|
|
13
|
+
* | Definition type | `def.node` | Returns |
|
|
14
|
+
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
15
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` (or `null`) |
|
|
16
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
17
|
+
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
18
|
+
* | `Parameter` | containing function node | `def.node` (if a real function) |
|
|
19
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
20
|
+
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
21
|
+
* | `ImportBinding` | import specifier | `null` |
|
|
22
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
23
|
+
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
24
|
+
* | `Type` | type alias node | `null` |
|
|
25
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
26
|
+
*
|
|
27
|
+
* @param context The ESLint rule context used for scope lookup.
|
|
28
|
+
* @param node The identifier to resolve.
|
|
29
|
+
* @param at Which definition to use when multiple exist (default: `0`; pass `-1` for the last).
|
|
30
|
+
* @param localOnly When `true`, look up the variable only in the node's own scope (faster, but
|
|
31
|
+
* will miss variables declared in an outer scope). When `false` (default), traverse the scope
|
|
32
|
+
* chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
33
|
+
* correctly.
|
|
34
|
+
* @returns The resolved node, or `null` if the identifier cannot be resolved to a value node.
|
|
35
|
+
*/
|
|
36
|
+
function resolve(context, node, at = 0, localOnly = false) {
|
|
37
|
+
const scope = context.sourceCode.getScope(node);
|
|
38
|
+
const variable = localOnly ? scope.set.get(node.name) : findVariable(scope, node);
|
|
39
|
+
if (variable == null) return null;
|
|
40
|
+
const def = variable.defs.at(at);
|
|
41
|
+
if (def == null) return null;
|
|
42
|
+
switch (def.type) {
|
|
43
|
+
case DefinitionType.FunctionName: return def.node;
|
|
44
|
+
case DefinitionType.ClassName: return def.node;
|
|
45
|
+
case DefinitionType.Variable: {
|
|
46
|
+
const { init } = def.node;
|
|
47
|
+
if (init == null) return null;
|
|
48
|
+
if ("declarations" in init) return null;
|
|
49
|
+
return init;
|
|
50
|
+
}
|
|
51
|
+
case DefinitionType.Parameter: return ast.isFunction(def.node) ? def.node : null;
|
|
52
|
+
case DefinitionType.TSEnumName: return def.node;
|
|
53
|
+
case DefinitionType.TSEnumMember: return def.node.initializer ?? null;
|
|
54
|
+
case DefinitionType.ImportBinding: return null;
|
|
55
|
+
case DefinitionType.CatchClause: return null;
|
|
56
|
+
case DefinitionType.TSModuleName: return null;
|
|
57
|
+
case DefinitionType.Type: return null;
|
|
58
|
+
case DefinitionType.ImplicitGlobalVariable: return null;
|
|
59
|
+
default: return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
7
64
|
//#region src/compute-object-type.ts
|
|
8
65
|
/**
|
|
9
66
|
* Detect the ObjectType of a given node
|
|
10
67
|
* @param node The node to check
|
|
11
|
-
* @param initialScope The initial scope to check for variable declarations
|
|
12
68
|
* @returns The ObjectType of the node, or undefined if not detected
|
|
13
69
|
*/
|
|
14
|
-
function computeObjectType(
|
|
15
|
-
if (node == null) return
|
|
70
|
+
function computeObjectType(context, node) {
|
|
71
|
+
if (node == null) return null;
|
|
16
72
|
switch (node.type) {
|
|
17
73
|
case AST_NODE_TYPES.JSXElement:
|
|
18
74
|
case AST_NODE_TYPES.JSXFragment: return {
|
|
@@ -47,43 +103,35 @@ function computeObjectType(node, initialScope) {
|
|
|
47
103
|
kind: "regexp",
|
|
48
104
|
node
|
|
49
105
|
};
|
|
50
|
-
return
|
|
106
|
+
return null;
|
|
51
107
|
case AST_NODE_TYPES.Identifier: {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
108
|
+
if ((context.sourceCode.getScope(node).set.get(node.name)?.defs.at(-1))?.type === DefinitionType.Parameter) return null;
|
|
109
|
+
const initNode = resolve(context, node, -1, true);
|
|
110
|
+
if (initNode == null) return null;
|
|
111
|
+
return computeObjectType(context, initNode);
|
|
55
112
|
}
|
|
56
113
|
case AST_NODE_TYPES.MemberExpression:
|
|
57
|
-
if (!("object" in node)) return
|
|
58
|
-
return computeObjectType(node.object
|
|
114
|
+
if (!("object" in node)) return null;
|
|
115
|
+
return computeObjectType(context, node.object);
|
|
59
116
|
case AST_NODE_TYPES.AssignmentExpression:
|
|
60
117
|
case AST_NODE_TYPES.AssignmentPattern:
|
|
61
|
-
if (!("right" in node)) return
|
|
62
|
-
return computeObjectType(node.right
|
|
63
|
-
case AST_NODE_TYPES.LogicalExpression: return computeObjectType(node.right
|
|
64
|
-
case AST_NODE_TYPES.ConditionalExpression: return computeObjectType(node.consequent
|
|
118
|
+
if (!("right" in node)) return null;
|
|
119
|
+
return computeObjectType(context, node.right);
|
|
120
|
+
case AST_NODE_TYPES.LogicalExpression: return computeObjectType(context, node.right);
|
|
121
|
+
case AST_NODE_TYPES.ConditionalExpression: return computeObjectType(context, node.consequent) ?? computeObjectType(context, node.alternate);
|
|
65
122
|
case AST_NODE_TYPES.SequenceExpression:
|
|
66
|
-
if (node.expressions.length === 0) return
|
|
67
|
-
return computeObjectType(node.expressions[node.expressions.length - 1]
|
|
123
|
+
if (node.expressions.length === 0) return null;
|
|
124
|
+
return computeObjectType(context, node.expressions[node.expressions.length - 1] ?? null);
|
|
68
125
|
case AST_NODE_TYPES.CallExpression: return {
|
|
69
126
|
kind: "unknown",
|
|
70
127
|
node,
|
|
71
128
|
reason: "call-expression"
|
|
72
129
|
};
|
|
73
130
|
default:
|
|
74
|
-
if (!("expression" in node) || typeof node.expression !== "object") return
|
|
75
|
-
return computeObjectType(node.expression
|
|
131
|
+
if (!("expression" in node) || typeof node.expression !== "object") return null;
|
|
132
|
+
return computeObjectType(context, node.expression);
|
|
76
133
|
}
|
|
77
134
|
}
|
|
78
|
-
function resolve(v) {
|
|
79
|
-
if (v == null) return unit;
|
|
80
|
-
const def = v.defs.at(-1);
|
|
81
|
-
if (def == null) return unit;
|
|
82
|
-
if (def.type === DefinitionType.Variable) return def.node.init;
|
|
83
|
-
if (def.type === DefinitionType.Parameter) return unit;
|
|
84
|
-
if (def.type === DefinitionType.ImportBinding) return unit;
|
|
85
|
-
return def.node;
|
|
86
|
-
}
|
|
87
135
|
|
|
88
136
|
//#endregion
|
|
89
137
|
//#region src/find-enclosing-assignment-target.ts
|
|
@@ -92,14 +140,14 @@ function resolve(v) {
|
|
|
92
140
|
*
|
|
93
141
|
* @todo Verify correctness and completeness of this function
|
|
94
142
|
* @param node The starting node
|
|
95
|
-
* @returns The enclosing assignment target node, or
|
|
143
|
+
* @returns The enclosing assignment target node, or null if not found
|
|
96
144
|
*/
|
|
97
145
|
function findEnclosingAssignmentTarget(node) {
|
|
98
146
|
switch (true) {
|
|
99
147
|
case node.type === AST_NODE_TYPES.VariableDeclarator: return node.id;
|
|
100
148
|
case node.type === AST_NODE_TYPES.AssignmentExpression: return node.left;
|
|
101
149
|
case node.type === AST_NODE_TYPES.PropertyDefinition: return node.key;
|
|
102
|
-
case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return
|
|
150
|
+
case node.type === AST_NODE_TYPES.BlockStatement || node.type === AST_NODE_TYPES.Program || node.parent === node: return null;
|
|
103
151
|
default: return findEnclosingAssignmentTarget(node.parent);
|
|
104
152
|
}
|
|
105
153
|
}
|
|
@@ -131,7 +179,7 @@ function isValueEqual(a, b, initialScopes) {
|
|
|
131
179
|
const aVar = findVariable(aScope, a);
|
|
132
180
|
const bVar = findVariable(bScope, b);
|
|
133
181
|
const resolve = (variable) => {
|
|
134
|
-
if (variable == null) return
|
|
182
|
+
if (variable == null) return null;
|
|
135
183
|
const def = variable.defs.at(0);
|
|
136
184
|
if (def != null) switch (true) {
|
|
137
185
|
case def.type === DefinitionType.FunctionName && def.node.type === AST_NODE_TYPES.FunctionDeclaration: return def.node;
|
|
@@ -139,7 +187,7 @@ function isValueEqual(a, b, initialScopes) {
|
|
|
139
187
|
case "init" in def.node && def.node.init != null && !("declarations" in def.node.init): return def.node.init;
|
|
140
188
|
}
|
|
141
189
|
if (def?.type === DefinitionType.Parameter && ast.isFunction(def.node)) return def.node;
|
|
142
|
-
return
|
|
190
|
+
return null;
|
|
143
191
|
};
|
|
144
192
|
const aVarInit = resolve(aVar);
|
|
145
193
|
const bVarInit = resolve(bVar);
|
|
@@ -197,4 +245,4 @@ function isAssignmentTargetEqual(context, a, b) {
|
|
|
197
245
|
}
|
|
198
246
|
|
|
199
247
|
//#endregion
|
|
200
|
-
export { computeObjectType, findEnclosingAssignmentTarget, isAssignmentTargetEqual, isValueEqual };
|
|
248
|
+
export { computeObjectType, findEnclosingAssignmentTarget, isAssignmentTargetEqual, isValueEqual, resolve };
|
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.64",
|
|
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,11 +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.
|
|
38
|
-
"@eslint-react/eff": "3.0.0-next.
|
|
39
|
-
"@eslint-react/shared": "3.0.0-next.
|
|
37
|
+
"@eslint-react/ast": "3.0.0-next.64",
|
|
38
|
+
"@eslint-react/eff": "3.0.0-next.64",
|
|
39
|
+
"@eslint-react/shared": "3.0.0-next.64"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@typescript-eslint/typescript-estree": "canary",
|
|
42
43
|
"tsdown": "^0.21.0-beta.2",
|
|
43
44
|
"@local/configs": "0.0.0"
|
|
44
45
|
},
|