@tanstack/eslint-plugin-query 5.91.4 → 5.94.4
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/package.json +5 -6
- package/src/rules/exhaustive-deps/exhaustive-deps.rule.ts +14 -14
- package/src/rules/exhaustive-deps/exhaustive-deps.utils.ts +159 -0
- package/src/utils/ast-utils.ts +13 -1
- package/build/legacy/chunk-MUQBIZ2R.js +0 -1027
- package/build/legacy/chunk-MUQBIZ2R.js.map +0 -1
- package/build/legacy/index.cjs +0 -1096
- package/build/legacy/index.cjs.map +0 -1
- package/build/legacy/index.d.cts +0 -52
- package/build/legacy/index.d.ts +0 -52
- package/build/legacy/index.js +0 -50
- package/build/legacy/index.js.map +0 -1
- package/build/legacy/rules.cjs +0 -1053
- package/build/legacy/rules.cjs.map +0 -1
- package/build/legacy/rules.d.cts +0 -6
- package/build/legacy/rules.d.ts +0 -6
- package/build/legacy/rules.js +0 -7
- package/build/legacy/rules.js.map +0 -1
- package/build/legacy/types.cjs +0 -19
- package/build/legacy/types.cjs.map +0 -1
- package/build/legacy/types.d.cts +0 -5
- package/build/legacy/types.d.ts +0 -5
- package/build/legacy/types.js +0 -1
- package/build/legacy/types.js.map +0 -1
- package/build/modern/chunk-2FPOGBVA.js +0 -1019
- package/build/modern/chunk-2FPOGBVA.js.map +0 -1
- package/build/modern/index.cjs +0 -1089
- package/build/modern/index.cjs.map +0 -1
- package/build/modern/index.d.cts +0 -52
- package/build/modern/index.d.ts +0 -52
- package/build/modern/index.js +0 -50
- package/build/modern/index.js.map +0 -1
- package/build/modern/rules.cjs +0 -1046
- package/build/modern/rules.cjs.map +0 -1
- package/build/modern/rules.d.cts +0 -6
- package/build/modern/rules.d.ts +0 -6
- package/build/modern/rules.js +0 -7
- package/build/modern/rules.js.map +0 -1
- package/build/modern/types.cjs +0 -20
- package/build/modern/types.cjs.map +0 -1
- package/build/modern/types.d.cts +0 -5
- package/build/modern/types.d.ts +0 -5
- package/build/modern/types.js +0 -1
- package/build/modern/types.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/eslint-plugin-query",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.94.4",
|
|
4
4
|
"description": "ESLint plugin for TanStack Query",
|
|
5
5
|
"author": "Eliya Cohen",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"eslint": "^8.57.0 || ^9.0.0",
|
|
54
|
-
"typescript": "^5.
|
|
54
|
+
"typescript": "^5.4.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependenciesMeta": {
|
|
57
57
|
"typescript": {
|
|
@@ -63,15 +63,14 @@
|
|
|
63
63
|
"compile": "tsc --build",
|
|
64
64
|
"test:eslint": "eslint --concurrency=auto ./src",
|
|
65
65
|
"test:types": "npm-run-all --serial test:types:*",
|
|
66
|
-
"test:types:ts50": "node ../../node_modules/typescript50/lib/tsc.js --build",
|
|
67
|
-
"test:types:ts51": "node ../../node_modules/typescript51/lib/tsc.js --build",
|
|
68
|
-
"test:types:ts52": "node ../../node_modules/typescript52/lib/tsc.js --build",
|
|
69
|
-
"test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js --build",
|
|
70
66
|
"test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js --build",
|
|
71
67
|
"test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js --build",
|
|
72
68
|
"test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js --build",
|
|
73
69
|
"test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js --build",
|
|
70
|
+
"test:types:ts58": "node ../../node_modules/typescript58/lib/tsc.js --build",
|
|
71
|
+
"test:types:ts59": "node ../../node_modules/typescript59/lib/tsc.js --build",
|
|
74
72
|
"test:types:tscurrent": "tsc --build",
|
|
73
|
+
"test:types:ts60": "node ../../node_modules/typescript60/lib/tsc.js --build",
|
|
75
74
|
"test:lib": "vitest",
|
|
76
75
|
"test:lib:dev": "pnpm run test:lib --watch",
|
|
77
76
|
"test:build": "publint --strict && attw --pack",
|
|
@@ -86,25 +86,27 @@ export const rule = createRule({
|
|
|
86
86
|
}),
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
const queryKeyDeps = ExhaustiveDepsUtils.collectQueryKeyDeps({
|
|
90
|
+
sourceCode: context.sourceCode,
|
|
91
|
+
scopeManager,
|
|
92
|
+
queryKeyNode,
|
|
93
|
+
})
|
|
93
94
|
|
|
94
95
|
const missingRefs = relevantRefs
|
|
95
96
|
.map((ref) => ({
|
|
96
97
|
ref: ref,
|
|
97
|
-
text: ASTUtils.
|
|
98
|
-
ref.identifier
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
text: ASTUtils.isAncestorIsCallee(ref.identifier)
|
|
99
|
+
? ref.identifier.name
|
|
100
|
+
: ASTUtils.mapKeyNodeToBaseText(
|
|
101
|
+
ref.identifier,
|
|
102
|
+
context.sourceCode,
|
|
103
|
+
),
|
|
101
104
|
}))
|
|
102
105
|
.filter(({ ref, text }) => {
|
|
103
106
|
return (
|
|
104
107
|
!ref.isTypeReference &&
|
|
105
|
-
!
|
|
106
|
-
!
|
|
107
|
-
!existingKeys.includes(text.split(/[?.]/)[0] ?? '')
|
|
108
|
+
!queryKeyDeps.has(text) &&
|
|
109
|
+
!queryKeyDeps.has(text.split(/[?.]/)[0] ?? '')
|
|
108
110
|
)
|
|
109
111
|
})
|
|
110
112
|
.map(({ ref, text }) => ({
|
|
@@ -116,9 +118,7 @@ export const rule = createRule({
|
|
|
116
118
|
|
|
117
119
|
if (uniqueMissingRefs.length > 0) {
|
|
118
120
|
const missingAsText = uniqueMissingRefs
|
|
119
|
-
.map((ref) =>
|
|
120
|
-
ASTUtils.mapKeyNodeToText(ref.identifier, context.sourceCode),
|
|
121
|
-
)
|
|
121
|
+
.map((ref) => ref.text)
|
|
122
122
|
.join(', ')
|
|
123
123
|
|
|
124
124
|
const queryKeyValue = context.sourceCode.getText(queryKeyNode)
|
|
@@ -12,6 +12,20 @@ export const ExhaustiveDepsUtils = {
|
|
|
12
12
|
}) {
|
|
13
13
|
const { sourceCode, reference, scopeManager, node, filename } = params
|
|
14
14
|
const component = ASTUtils.getFunctionAncestor(sourceCode, node)
|
|
15
|
+
const queryFnScope = scopeManager.acquire(node)
|
|
16
|
+
|
|
17
|
+
if (queryFnScope === null) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let currentScope = reference.resolved?.scope ?? null
|
|
22
|
+
while (currentScope !== null) {
|
|
23
|
+
if (currentScope === queryFnScope) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
currentScope = currentScope.upper
|
|
28
|
+
}
|
|
15
29
|
|
|
16
30
|
if (component !== undefined) {
|
|
17
31
|
if (
|
|
@@ -51,4 +65,149 @@ export const ExhaustiveDepsUtils = {
|
|
|
51
65
|
node.operator === 'instanceof'
|
|
52
66
|
)
|
|
53
67
|
},
|
|
68
|
+
|
|
69
|
+
collectQueryKeyDeps(params: {
|
|
70
|
+
sourceCode: Readonly<TSESLint.SourceCode>
|
|
71
|
+
scopeManager: TSESLint.Scope.ScopeManager
|
|
72
|
+
queryKeyNode: TSESTree.Node
|
|
73
|
+
}): Set<string> {
|
|
74
|
+
const { sourceCode, scopeManager, queryKeyNode } = params
|
|
75
|
+
const deps = new Set<string>()
|
|
76
|
+
const visitorKeys = sourceCode.visitorKeys
|
|
77
|
+
|
|
78
|
+
function add(identifier: TSESTree.Identifier) {
|
|
79
|
+
deps.add(ASTUtils.mapKeyNodeToBaseText(identifier, sourceCode))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function visitChildren(node: TSESTree.Node): void {
|
|
83
|
+
const keys = (visitorKeys[node.type] ?? []) as ReadonlyArray<
|
|
84
|
+
keyof TSESTree.Node
|
|
85
|
+
>
|
|
86
|
+
|
|
87
|
+
for (const key of keys) {
|
|
88
|
+
const value = node[key]
|
|
89
|
+
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
for (const item of value) {
|
|
92
|
+
if (ExhaustiveDepsUtils.isNode(item)) {
|
|
93
|
+
visit(item)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (ExhaustiveDepsUtils.isNode(value)) {
|
|
100
|
+
visit(value)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function visit(node: TSESTree.Node | null | undefined): void {
|
|
106
|
+
if (!node) return
|
|
107
|
+
|
|
108
|
+
switch (node.type) {
|
|
109
|
+
case AST_NODE_TYPES.Identifier:
|
|
110
|
+
add(node)
|
|
111
|
+
return
|
|
112
|
+
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
113
|
+
case AST_NODE_TYPES.FunctionExpression:
|
|
114
|
+
for (const reference of ExhaustiveDepsUtils.collectExternalRefsInFunction(
|
|
115
|
+
{
|
|
116
|
+
functionNode: node,
|
|
117
|
+
scopeManager: scopeManager,
|
|
118
|
+
},
|
|
119
|
+
)) {
|
|
120
|
+
if (reference.identifier.type === AST_NODE_TYPES.Identifier) {
|
|
121
|
+
add(reference.identifier)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return
|
|
125
|
+
case AST_NODE_TYPES.Property:
|
|
126
|
+
visit(node.value)
|
|
127
|
+
return
|
|
128
|
+
case AST_NODE_TYPES.MemberExpression:
|
|
129
|
+
if (
|
|
130
|
+
node.parent.type === AST_NODE_TYPES.CallExpression &&
|
|
131
|
+
node.parent.callee === node &&
|
|
132
|
+
node.object.type === AST_NODE_TYPES.Identifier
|
|
133
|
+
) {
|
|
134
|
+
deps.add(node.object.name)
|
|
135
|
+
} else {
|
|
136
|
+
visit(node.object)
|
|
137
|
+
}
|
|
138
|
+
return
|
|
139
|
+
case AST_NODE_TYPES.CallExpression:
|
|
140
|
+
node.arguments.forEach((argument) => visit(argument))
|
|
141
|
+
if (
|
|
142
|
+
node.callee.type === AST_NODE_TYPES.MemberExpression ||
|
|
143
|
+
node.callee.type === AST_NODE_TYPES.ChainExpression ||
|
|
144
|
+
node.callee.type === AST_NODE_TYPES.TSNonNullExpression
|
|
145
|
+
) {
|
|
146
|
+
visit(node.callee)
|
|
147
|
+
}
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
visitChildren(node)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
visit(queryKeyNode)
|
|
155
|
+
|
|
156
|
+
return deps
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
isNode(value: unknown): value is TSESTree.Node {
|
|
160
|
+
return (
|
|
161
|
+
typeof value === 'object' &&
|
|
162
|
+
value !== null &&
|
|
163
|
+
'type' in value &&
|
|
164
|
+
typeof value.type === 'string'
|
|
165
|
+
)
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
collectExternalRefsInFunction(params: {
|
|
169
|
+
functionNode: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression
|
|
170
|
+
scopeManager: TSESLint.Scope.ScopeManager
|
|
171
|
+
}): Array<TSESLint.Scope.Reference> {
|
|
172
|
+
const { functionNode, scopeManager } = params
|
|
173
|
+
const functionScope = scopeManager.acquire(functionNode)
|
|
174
|
+
|
|
175
|
+
if (functionScope === null) {
|
|
176
|
+
return []
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const externalRefs: Array<TSESLint.Scope.Reference> = []
|
|
180
|
+
|
|
181
|
+
function collect(scope: TSESLint.Scope.Scope) {
|
|
182
|
+
for (const reference of scope.references) {
|
|
183
|
+
if (!reference.isRead() || reference.resolved === null) {
|
|
184
|
+
continue
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let currentScope: TSESLint.Scope.Scope | null = reference.resolved.scope
|
|
188
|
+
let declaredInsideFunction = false
|
|
189
|
+
|
|
190
|
+
while (currentScope !== null) {
|
|
191
|
+
if (currentScope === functionScope) {
|
|
192
|
+
declaredInsideFunction = true
|
|
193
|
+
break
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
currentScope = currentScope.upper
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (!declaredInsideFunction) {
|
|
200
|
+
externalRefs.push(reference)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (const childScope of scope.childScopes) {
|
|
205
|
+
collect(childScope)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
collect(functionScope)
|
|
210
|
+
|
|
211
|
+
return externalRefs
|
|
212
|
+
},
|
|
54
213
|
}
|
package/src/utils/ast-utils.ts
CHANGED
|
@@ -192,7 +192,19 @@ export const ASTUtils = {
|
|
|
192
192
|
return []
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
const
|
|
195
|
+
const collectReferences = (
|
|
196
|
+
currentScope: TSESLint.Scope.Scope,
|
|
197
|
+
): Array<TSESLint.Scope.Reference> => {
|
|
198
|
+
const references = [...currentScope.references]
|
|
199
|
+
|
|
200
|
+
for (const childScope of currentScope.childScopes) {
|
|
201
|
+
references.push(...collectReferences(childScope))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return references
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const references = collectReferences(scope)
|
|
196
208
|
.filter((x) => x.isRead() && !scope.set.has(x.identifier.name))
|
|
197
209
|
.map((x) => {
|
|
198
210
|
const referenceNode = ASTUtils.traverseUpOnly(x.identifier, [
|