@@ -3,7 +3,7 @@ import type { AST } from "svelte-eslint-parser"
3
3
import { ReferenceTracker } from "eslint-utils"
4
4
import { createRule } from "../utils"
5
5
import type { RuleContext } from "../types"
6
- import { getScope } from "../utils/ast-utils"
6
+ import { findVariable } from "../utils/ast-utils"
7
7
import { traverseNodes } from "svelte-eslint-parser"
8
8
9
9
/**
@@ -74,40 +74,15 @@ function isFunctionCall(node: TSESTree.Node): boolean {
74
74
return parent . callee . type === "Identifier" && parent . callee . name === node . name
75
75
}
76
76
77
- /**
78
- * Return true if `node` is a variable.
79
- *
80
- * e.g. foo.bar
81
- * If node is `foo`, return true.
82
- * If node is `bar`, return false.
83
- *
84
- * e.g. let baz = 1
85
- * If node is `baz`, return true.
86
- */
87
- function isVariableNode ( node : TSESTree . Identifier ) : boolean {
88
- const { parent } = node
89
- if ( parent ?. type !== "MemberExpression" ) return true
90
- if (
91
- parent . type === "MemberExpression" &&
92
- parent . object . type !== "Identifier"
93
- ) {
94
- return false
95
- }
96
-
97
- return parent . object . type !== "Identifier"
98
- ? false
99
- : parent . object . name === node . name
100
- }
101
-
102
77
/**
103
78
* Return true if `node` is a reactive variable.
104
79
*/
105
80
function isReactiveVariableNode (
106
- context : RuleContext ,
81
+ reactiveVariableReferences : TSESTree . Identifier [ ] ,
107
82
node : TSESTree . Node ,
108
83
) : node is TSESTree . Identifier {
109
84
if ( node . type !== "Identifier" ) return false
110
- return getAllReactiveVariableReferences ( context ) . includes ( node )
85
+ return reactiveVariableReferences . includes ( node )
111
86
}
112
87
113
88
/**
@@ -146,11 +121,10 @@ function isPromiseThenOrCatchBody(node: TSESTree.Node): boolean {
146
121
return [ "then" , "catch" ] . includes ( property . name )
147
122
}
148
123
149
-
150
124
/**
151
125
* Get all reactive variable reference.
152
126
*/
153
- function getAllReactiveVariableReferences ( context : RuleContext ) {
127
+ function getReactiveVariableReferences ( context : RuleContext ) {
154
128
const scopeManager = context . getSourceCode ( ) . scopeManager
155
129
// Find the top-level (module or global) scope.
156
130
// Any variable defined at the top-level (module scope or global scope) can be made reactive.
@@ -181,18 +155,18 @@ function getAllReactiveVariableReferences(context: RuleContext) {
181
155
* Get all tracked reactive variables.
182
156
*/
183
157
function getTrackedVariableNodes (
184
- context : RuleContext ,
158
+ reactiveVariableReferences : TSESTree . Identifier [ ] ,
185
159
ast : AST . SvelteReactiveStatement ,
186
160
) {
187
- const reactiveVariableNodes : TSESTree . Identifier [ ] = [ ]
188
- for ( const identifier of getAllReactiveVariableReferences ( context ) ) {
161
+ const reactiveVariableNodes : Set < TSESTree . Identifier > = new Set ( )
162
+ for ( const identifier of reactiveVariableReferences ) {
189
163
if (
190
164
// If the identifier is within the reactive statement range,
191
165
// it is used within the reactive statement.
192
166
ast . range [ 0 ] <= identifier . range [ 0 ] &&
193
167
identifier . range [ 1 ] <= ast . range [ 1 ]
194
168
) {
195
- reactiveVariableNodes . push ( identifier )
169
+ reactiveVariableNodes . add ( identifier )
196
170
}
197
171
}
198
172
return reactiveVariableNodes
@@ -293,6 +267,7 @@ function doLint(
293
267
name : string
294
268
} [ ] ,
295
269
reactiveVariableNames : string [ ] ,
270
+ reactiveVariableReferences : TSESTree . Identifier [ ] ,
296
271
pIsSameTask : boolean ,
297
272
) {
298
273
let isSameMicroTask = pIsSameTask
@@ -325,7 +300,10 @@ function doLint(
325
300
326
301
if ( node . type === "Identifier" && isFunctionCall ( node ) ) {
327
302
// traverse used functions body
328
- const functionDeclarationNode = getFunctionDeclarationNode ( node )
303
+ const functionDeclarationNode = getFunctionDeclarationNode (
304
+ context ,
305
+ node ,
306
+ )
329
307
if ( functionDeclarationNode ) {
330
308
doLint (
331
309
context ,
@@ -334,14 +312,15 @@ function doLint(
334
312
tickCallExpressions ,
335
313
taskReferences ,
336
314
reactiveVariableNames ,
315
+ reactiveVariableReferences ,
337
316
isSameMicroTask ,
338
317
)
339
318
}
340
319
}
341
320
342
321
if ( ! isSameMicroTask ) {
343
322
if (
344
- isReactiveVariableNode ( context , node ) &&
323
+ isReactiveVariableNode ( reactiveVariableReferences , node ) &&
345
324
reactiveVariableNames . includes ( node . name ) &&
346
325
isNodeForAssign ( node )
347
326
) {
@@ -425,14 +404,21 @@ export default createRule("infinite-reactive-loop", {
425
404
[ "SvelteReactiveStatement" ] : ( ast : AST . SvelteReactiveStatement ) => {
426
405
const tickCallExpressions = extractTickReferences ( context )
427
406
const taskReferences = extractTaskReferences ( context )
428
- const trackedVariableNodes = getTrackedVariableNodes ( context , ast )
407
+ const reactiveVariableReferences =
408
+ getReactiveVariableReferences ( context )
409
+ const trackedVariableNodes = getTrackedVariableNodes (
410
+ reactiveVariableReferences ,
411
+ ast ,
412
+ )
413
+
429
414
doLint (
430
415
context ,
431
416
ast . body ,
432
417
[ ] ,
433
418
tickCallExpressions ,
434
419
taskReferences ,
435
- trackedVariableNodes . map ( ( node ) => node . name ) ,
420
+ Array . from ( trackedVariableNodes ) . map ( ( node ) => node . name ) ,
421
+ reactiveVariableReferences ,
436
422
true ,
437
423
)
438
424
} ,
0 commit comments