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