@eslint-react/var 5.20.4 → 5.20.6
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 +64 -14
- package/dist/index.js +94 -19
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface ImportEntry {
|
|
|
36
36
|
* time, and results preserve source order.
|
|
37
37
|
*/
|
|
38
38
|
export interface ImportLookup {
|
|
39
|
+
/** Return every import entry, in source order. */
|
|
40
|
+
all(): readonly ImportEntry[];
|
|
39
41
|
/**
|
|
40
42
|
* Look up the import entry a local name is bound to.
|
|
41
43
|
*
|
|
@@ -50,8 +52,6 @@ export interface ImportLookup {
|
|
|
50
52
|
* @returns The matching entries in source order, possibly empty.
|
|
51
53
|
*/
|
|
52
54
|
bindingsOf(name: string): readonly ImportEntry[];
|
|
53
|
-
/** Return every import entry, in source order. */
|
|
54
|
-
all(): readonly ImportEntry[];
|
|
55
55
|
/**
|
|
56
56
|
* Check whether a local name is bound to a specific imported export.
|
|
57
57
|
*
|
|
@@ -69,6 +69,11 @@ export interface ImportLookup {
|
|
|
69
69
|
}
|
|
70
70
|
/** Options for {@link createImportLookup}. */
|
|
71
71
|
export interface ImportLookupOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Local names to pre-register as namespace bindings without an import
|
|
74
|
+
* statement, e.g. a `ReactDOM` global provided by the environment.
|
|
75
|
+
*/
|
|
76
|
+
builtinNamespaces?: readonly string[];
|
|
72
77
|
/**
|
|
73
78
|
* The base import source to track, e.g. `"react-dom"`.
|
|
74
79
|
*
|
|
@@ -76,11 +81,6 @@ export interface ImportLookupOptions {
|
|
|
76
81
|
* matches a source of `"react-dom"`.
|
|
77
82
|
*/
|
|
78
83
|
source: string;
|
|
79
|
-
/**
|
|
80
|
-
* Local names to pre-register as namespace bindings without an import
|
|
81
|
-
* statement, e.g. a `ReactDOM` global provided by the environment.
|
|
82
|
-
*/
|
|
83
|
-
builtinNamespaces?: readonly string[];
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Create a lookup of local import bindings from a source by scanning the
|
|
@@ -171,17 +171,17 @@ export declare function isValueEqual(context: RuleContext, a: TSESTree.Node, b:
|
|
|
171
171
|
*
|
|
172
172
|
* | Definition type | `def.node` | Returns |
|
|
173
173
|
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
174
|
-
* | `
|
|
175
|
-
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
174
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
176
175
|
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
177
|
-
* | `
|
|
178
|
-
* | `
|
|
179
|
-
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
176
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
177
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
180
178
|
* | `ImportBinding` | import specifier | `null` |
|
|
181
|
-
* | `
|
|
179
|
+
* | `Parameter` | containing function node | `null` (the value is supplied by the caller) |
|
|
180
|
+
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
181
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
182
182
|
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
183
183
|
* | `Type` | type alias node | `null` |
|
|
184
|
-
* | `
|
|
184
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` for a plain identifier binding; `null` for destructured bindings or missing init |
|
|
185
185
|
*
|
|
186
186
|
* @param context The ESLint rule context.
|
|
187
187
|
* @param node The identifier to resolve.
|
|
@@ -192,6 +192,9 @@ export declare function isValueEqual(context: RuleContext, a: TSESTree.Node, b:
|
|
|
192
192
|
* scope chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
193
193
|
* correctly.
|
|
194
194
|
* @returns The resolved node, or `null` if the identifier cannot be resolved to a value node.
|
|
195
|
+
*
|
|
196
|
+
* For origin/pedigree tracking that maps destructured bindings to the declarator's
|
|
197
|
+
* initializer, see {@link resolveOrigin}.
|
|
195
198
|
*/
|
|
196
199
|
export declare function resolve(context: RuleContext, node: TSESTree.Identifier, options?: Partial<{
|
|
197
200
|
at: number;
|
|
@@ -255,4 +258,51 @@ export type ObjectType = {
|
|
|
255
258
|
* @returns The object type of the node, or `null` when it cannot be resolved.
|
|
256
259
|
*/
|
|
257
260
|
export declare function resolveObjectType(context: RuleContext, node: TSESTree.Node | null): ObjectType | null;
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/resolve-origin.d.ts
|
|
263
|
+
/**
|
|
264
|
+
* Resolve an identifier to the AST node its value **originates from**,
|
|
265
|
+
* suitable for origin/pedigree tracking in ESLint rule analysis.
|
|
266
|
+
*
|
|
267
|
+
* The resolution follows these rules per definition type:
|
|
268
|
+
*
|
|
269
|
+
* | Definition type | `def.node` | Returns |
|
|
270
|
+
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
271
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
272
|
+
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
273
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
274
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
275
|
+
* | `ImportBinding` | import specifier | `def.node` (the import specifier) |
|
|
276
|
+
* | `Parameter` | containing function node | `def.node` (if a real function) |
|
|
277
|
+
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
278
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
279
|
+
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
280
|
+
* | `Type` | type alias node | `null` |
|
|
281
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` (or `null`), including for destructured bindings |
|
|
282
|
+
*
|
|
283
|
+
* Unlike {@link resolve}, a binding declared through a destructuring
|
|
284
|
+
* pattern (e.g. `setState` in `const [state, setState] = useState()`) resolves to the
|
|
285
|
+
* declarator's initializer (the `useState()` call), i.e. the source expression the
|
|
286
|
+
* binding derives from rather than the binding's own value; and a parameter resolves
|
|
287
|
+
* to the containing function node (the binding's declaration site) instead of `null`;
|
|
288
|
+
* and an import binding resolves to its import specifier (whose parent
|
|
289
|
+
* `ImportDeclaration` carries the module source) instead of `null`.
|
|
290
|
+
*
|
|
291
|
+
* Use this for origin/pedigree tracking ("what produced this value?"); use
|
|
292
|
+
* {@link resolve} when the precise value of the binding is needed.
|
|
293
|
+
*
|
|
294
|
+
* @param context The ESLint rule context.
|
|
295
|
+
* @param node The identifier to resolve.
|
|
296
|
+
* @param options Optional settings:
|
|
297
|
+
* - `at`: Index of the definition to resolve (default: `0` for the first definition).
|
|
298
|
+
* - `localOnly`: If `true`, only consider variables declared in the same scope as the identifier
|
|
299
|
+
* (this will miss variables declared in an outer scope). When `false` (default), traverse the
|
|
300
|
+
* scope chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
301
|
+
* correctly.
|
|
302
|
+
* @returns The resolved origin node, or `null` if the identifier cannot be resolved.
|
|
303
|
+
*/
|
|
304
|
+
export declare function resolveOrigin(context: RuleContext, node: TSESTree.Identifier, options?: Partial<{
|
|
305
|
+
at: number;
|
|
306
|
+
localOnly: boolean;
|
|
307
|
+
}>): TSESTree.Node | null;
|
|
258
308
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -512,7 +512,7 @@ const takeWhile = dual(2, (xs, pred) => {
|
|
|
512
512
|
* ```
|
|
513
513
|
*/
|
|
514
514
|
function createImportLookup(program, options) {
|
|
515
|
-
const {
|
|
515
|
+
const { builtinNamespaces = [], source } = options;
|
|
516
516
|
const entries = [];
|
|
517
517
|
const byLocal = /* @__PURE__ */ new Map();
|
|
518
518
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -563,15 +563,15 @@ function createImportLookup(program, options) {
|
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
return {
|
|
566
|
+
all() {
|
|
567
|
+
return entries;
|
|
568
|
+
},
|
|
566
569
|
binding(local) {
|
|
567
570
|
return byLocal.get(local);
|
|
568
571
|
},
|
|
569
572
|
bindingsOf(name) {
|
|
570
573
|
return byName.get(name) ?? [];
|
|
571
574
|
},
|
|
572
|
-
all() {
|
|
573
|
-
return entries;
|
|
574
|
-
},
|
|
575
575
|
has(local, name) {
|
|
576
576
|
return byLocal.get(local)?.name === name;
|
|
577
577
|
},
|
|
@@ -602,26 +602,37 @@ function getRequireExpressionArguments(node) {
|
|
|
602
602
|
}
|
|
603
603
|
|
|
604
604
|
//#endregion
|
|
605
|
-
//#region src/resolve.ts
|
|
605
|
+
//#region src/resolve-origin.ts
|
|
606
606
|
/**
|
|
607
|
-
* Resolve an identifier to the AST node
|
|
608
|
-
* suitable for
|
|
607
|
+
* Resolve an identifier to the AST node its value **originates from**,
|
|
608
|
+
* suitable for origin/pedigree tracking in ESLint rule analysis.
|
|
609
609
|
*
|
|
610
610
|
* The resolution follows these rules per definition type:
|
|
611
611
|
*
|
|
612
612
|
* | Definition type | `def.node` | Returns |
|
|
613
613
|
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
614
|
-
* | `
|
|
615
|
-
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
614
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
616
615
|
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
616
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
617
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
618
|
+
* | `ImportBinding` | import specifier | `def.node` (the import specifier) |
|
|
617
619
|
* | `Parameter` | containing function node | `def.node` (if a real function) |
|
|
618
|
-
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
619
620
|
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
620
|
-
* | `
|
|
621
|
-
* | `CatchClause` | `CatchClause` | `null` |
|
|
621
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
622
622
|
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
623
623
|
* | `Type` | type alias node | `null` |
|
|
624
|
-
* | `
|
|
624
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` (or `null`), including for destructured bindings |
|
|
625
|
+
*
|
|
626
|
+
* Unlike {@link resolve}, a binding declared through a destructuring
|
|
627
|
+
* pattern (e.g. `setState` in `const [state, setState] = useState()`) resolves to the
|
|
628
|
+
* declarator's initializer (the `useState()` call), i.e. the source expression the
|
|
629
|
+
* binding derives from rather than the binding's own value; and a parameter resolves
|
|
630
|
+
* to the containing function node (the binding's declaration site) instead of `null`;
|
|
631
|
+
* and an import binding resolves to its import specifier (whose parent
|
|
632
|
+
* `ImportDeclaration` carries the module source) instead of `null`.
|
|
633
|
+
*
|
|
634
|
+
* Use this for origin/pedigree tracking ("what produced this value?"); use
|
|
635
|
+
* {@link resolve} when the precise value of the binding is needed.
|
|
625
636
|
*
|
|
626
637
|
* @param context The ESLint rule context.
|
|
627
638
|
* @param node The identifier to resolve.
|
|
@@ -631,9 +642,9 @@ function getRequireExpressionArguments(node) {
|
|
|
631
642
|
* (this will miss variables declared in an outer scope). When `false` (default), traverse the
|
|
632
643
|
* scope chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
633
644
|
* correctly.
|
|
634
|
-
* @returns The resolved node, or `null` if the identifier cannot be resolved
|
|
645
|
+
* @returns The resolved origin node, or `null` if the identifier cannot be resolved.
|
|
635
646
|
*/
|
|
636
|
-
function
|
|
647
|
+
function resolveOrigin(context, node, options) {
|
|
637
648
|
const { at = 0, localOnly = false } = options ?? {};
|
|
638
649
|
const scope = context.sourceCode.getScope(node);
|
|
639
650
|
const variable = localOnly ? scope.set.get(node.name) : findVariable(scope, node);
|
|
@@ -652,7 +663,7 @@ function resolve(context, node, options) {
|
|
|
652
663
|
case DefinitionType.Parameter: return Check.isFunction(def.node) ? def.node : null;
|
|
653
664
|
case DefinitionType.TSEnumName: return def.node;
|
|
654
665
|
case DefinitionType.TSEnumMember: return def.node.initializer ?? null;
|
|
655
|
-
case DefinitionType.ImportBinding: return
|
|
666
|
+
case DefinitionType.ImportBinding: return def.node;
|
|
656
667
|
case DefinitionType.CatchClause: return null;
|
|
657
668
|
case DefinitionType.TSModuleName: return null;
|
|
658
669
|
case DefinitionType.Type: return null;
|
|
@@ -685,8 +696,8 @@ function isValueEqual(context, a, b) {
|
|
|
685
696
|
case a.type === AST_NODE_TYPES.Literal && b.type === AST_NODE_TYPES.Literal: return a.value === b.value;
|
|
686
697
|
case a.type === AST_NODE_TYPES.TemplateElement && b.type === AST_NODE_TYPES.TemplateElement: return a.value.cooked === b.value.cooked;
|
|
687
698
|
case Check.isIdentifier(a) && Check.isIdentifier(b): {
|
|
688
|
-
const aDefNode =
|
|
689
|
-
const bDefNode =
|
|
699
|
+
const aDefNode = resolveOrigin(context, a);
|
|
700
|
+
const bDefNode = resolveOrigin(context, b);
|
|
690
701
|
const aDefNodeParent = aDefNode?.parent;
|
|
691
702
|
const bDefNodeParent = bDefNode?.parent;
|
|
692
703
|
const aVar = findVariable(aScope, a);
|
|
@@ -805,6 +816,70 @@ function isInitializedFromReactNative(name, initialScope, importSource = "react-
|
|
|
805
816
|
].includes(name.toLowerCase()) || Boolean(resolveImportSource(name, initialScope)?.startsWith(importSource));
|
|
806
817
|
}
|
|
807
818
|
|
|
819
|
+
//#endregion
|
|
820
|
+
//#region src/resolve.ts
|
|
821
|
+
/**
|
|
822
|
+
* Resolve an identifier to the AST node that represents its value,
|
|
823
|
+
* suitable for use in ESLint rule analysis.
|
|
824
|
+
*
|
|
825
|
+
* The resolution follows these rules per definition type:
|
|
826
|
+
*
|
|
827
|
+
* | Definition type | `def.node` | Returns |
|
|
828
|
+
* |--------------------------|----------------------------------------------|------------------------------------|
|
|
829
|
+
* | `CatchClause` | `CatchClause` | `null` |
|
|
830
|
+
* | `ClassName` | `ClassDeclaration` / `ClassExpression` | `def.node` |
|
|
831
|
+
* | `FunctionName` | `FunctionDeclaration` / `FunctionExpression` | `def.node` |
|
|
832
|
+
* | `ImplicitGlobalVariable` | any node | `null` |
|
|
833
|
+
* | `ImportBinding` | import specifier | `null` |
|
|
834
|
+
* | `Parameter` | containing function node | `null` (the value is supplied by the caller) |
|
|
835
|
+
* | `TSEnumMember` | `TSEnumMember` | `def.node.initializer` (or `null`) |
|
|
836
|
+
* | `TSEnumName` | `TSEnumDeclaration` | `def.node` |
|
|
837
|
+
* | `TSModuleName` | `TSModuleDeclaration` | `null` |
|
|
838
|
+
* | `Type` | type alias node | `null` |
|
|
839
|
+
* | `Variable` | `VariableDeclarator` | `def.node.init` for a plain identifier binding; `null` for destructured bindings or missing init |
|
|
840
|
+
*
|
|
841
|
+
* @param context The ESLint rule context.
|
|
842
|
+
* @param node The identifier to resolve.
|
|
843
|
+
* @param options Optional settings:
|
|
844
|
+
* - `at`: Index of the definition to resolve (default: `0` for the first definition).
|
|
845
|
+
* - `localOnly`: If `true`, only consider variables declared in the same scope as the identifier
|
|
846
|
+
* (this will miss variables declared in an outer scope). When `false` (default), traverse the
|
|
847
|
+
* scope chain upward via `findVariable` so that references to outer-scope bindings are resolved
|
|
848
|
+
* correctly.
|
|
849
|
+
* @returns The resolved node, or `null` if the identifier cannot be resolved to a value node.
|
|
850
|
+
*
|
|
851
|
+
* For origin/pedigree tracking that maps destructured bindings to the declarator's
|
|
852
|
+
* initializer, see {@link resolveOrigin}.
|
|
853
|
+
*/
|
|
854
|
+
function resolve(context, node, options) {
|
|
855
|
+
const { at = 0, localOnly = false } = options ?? {};
|
|
856
|
+
const scope = context.sourceCode.getScope(node);
|
|
857
|
+
const variable = localOnly ? scope.set.get(node.name) : findVariable(scope, node);
|
|
858
|
+
if (variable == null) return null;
|
|
859
|
+
const def = variable.defs.at(at);
|
|
860
|
+
if (def == null) return null;
|
|
861
|
+
switch (def.type) {
|
|
862
|
+
case DefinitionType.FunctionName: return def.node;
|
|
863
|
+
case DefinitionType.ClassName: return def.node;
|
|
864
|
+
case DefinitionType.Variable: {
|
|
865
|
+
const { id, init } = def.node;
|
|
866
|
+
if (id !== def.name) return null;
|
|
867
|
+
if (init == null) return null;
|
|
868
|
+
if ("declarations" in init) return null;
|
|
869
|
+
return init;
|
|
870
|
+
}
|
|
871
|
+
case DefinitionType.Parameter: return null;
|
|
872
|
+
case DefinitionType.TSEnumName: return def.node;
|
|
873
|
+
case DefinitionType.TSEnumMember: return def.node.initializer ?? null;
|
|
874
|
+
case DefinitionType.ImportBinding: return null;
|
|
875
|
+
case DefinitionType.CatchClause: return null;
|
|
876
|
+
case DefinitionType.TSModuleName: return null;
|
|
877
|
+
case DefinitionType.Type: return null;
|
|
878
|
+
case DefinitionType.ImplicitGlobalVariable: return null;
|
|
879
|
+
default: return null;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
808
883
|
//#endregion
|
|
809
884
|
//#region src/resolve-enclosing-assignment-target.ts
|
|
810
885
|
/**
|
|
@@ -934,4 +1009,4 @@ function resolveObjectType(context, node) {
|
|
|
934
1009
|
}
|
|
935
1010
|
|
|
936
1011
|
//#endregion
|
|
937
|
-
export { createImportLookup, getRequireExpressionArguments, isAssignmentTargetEqual, isInitializedFromReact, isInitializedFromReactNative, isValueEqual, resolve, resolveEnclosingAssignmentTarget, resolveImportSource, resolveObjectType };
|
|
1012
|
+
export { createImportLookup, getRequireExpressionArguments, isAssignmentTargetEqual, isInitializedFromReact, isInitializedFromReactNative, isValueEqual, resolve, resolveEnclosingAssignmentTarget, resolveImportSource, resolveObjectType, resolveOrigin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-react/var",
|
|
3
|
-
"version": "5.20.
|
|
3
|
+
"version": "5.20.6",
|
|
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": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@eslint-react/ast": "5.20.
|
|
33
|
-
"@eslint-react/eslint": "5.20.
|
|
32
|
+
"@eslint-react/ast": "5.20.6",
|
|
33
|
+
"@eslint-react/eslint": "5.20.6",
|
|
34
34
|
"@typescript-eslint/scope-manager": "^8.70.0",
|
|
35
35
|
"@typescript-eslint/types": "^8.70.0",
|
|
36
36
|
"@typescript-eslint/utils": "^8.70.0",
|