@@ -51,6 +51,7 @@ export default createRule('prefer-svelte-reactivity', {
51
51
create ( context ) {
52
52
const ignoreEncapsulatedLocalVariables =
53
53
context . options [ 0 ] ?. ignoreEncapsulatedLocalVariables ?? true ;
54
+ const returnedFunctionCalls : Map < FunctionLike , TSESTree . MethodDefinition [ ] > = new Map ( ) ;
54
55
const returnedVariables : Map < FunctionLike , VariableLike [ ] > = new Map ( ) ;
55
56
const exportedVars : TSESTree . Node [ ] = [ ] ;
56
57
return {
@@ -81,6 +82,29 @@ export default createRule('prefer-svelte-reactivity', {
81
82
}
82
83
} ) ,
83
84
Identifier ( node ) {
85
+ function recordVariable ( enclosingFunction : FunctionLike , variable : VariableLike ) : void {
86
+ if ( variable === null ) {
87
+ return ;
88
+ }
89
+ if ( ! returnedVariables . has ( enclosingFunction ) ) {
90
+ returnedVariables . set ( enclosingFunction , [ ] ) ;
91
+ }
92
+ returnedVariables . get ( enclosingFunction ) ?. push ( variable ) ;
93
+ }
94
+
95
+ function recordFunctionCall (
96
+ enclosingFunction : FunctionLike ,
97
+ functionCall : TSESTree . MethodDefinition
98
+ ) : void {
99
+ if ( functionCall === null ) {
100
+ return ;
101
+ }
102
+ if ( ! returnedFunctionCalls . has ( enclosingFunction ) ) {
103
+ returnedFunctionCalls . set ( enclosingFunction , [ ] ) ;
104
+ }
105
+ returnedFunctionCalls . get ( enclosingFunction ) ?. push ( functionCall ) ;
106
+ }
107
+
84
108
const enclosingReturn = findEnclosingReturn ( node ) ;
85
109
if ( enclosingReturn === null ) {
86
110
return ;
@@ -89,7 +113,6 @@ export default createRule('prefer-svelte-reactivity', {
89
113
if ( enclosingFunction === null ) {
90
114
return ;
91
115
}
92
- let variableDeclaration = null ;
93
116
if ( node . parent . type === 'MemberExpression' ) {
94
117
const enclosingClassBody = findEnclosingClassBody ( node ) ;
95
118
for ( const classElement of enclosingClassBody ?. body ?? [ ] ) {
@@ -98,7 +121,14 @@ export default createRule('prefer-svelte-reactivity', {
98
121
classElement . key . type === 'Identifier' &&
99
122
node . name === classElement . key . name
100
123
) {
101
- variableDeclaration = classElement ;
124
+ recordVariable ( enclosingFunction , classElement ) ;
125
+ }
126
+ if (
127
+ classElement . type === 'MethodDefinition' &&
128
+ classElement . key . type === 'Identifier' &&
129
+ node . name === classElement . key . name
130
+ ) {
131
+ recordFunctionCall ( enclosingFunction , classElement ) ;
102
132
}
103
133
}
104
134
} else {
@@ -108,16 +138,9 @@ export default createRule('prefer-svelte-reactivity', {
108
138
variable . identifiers . length > 0 &&
109
139
variable . identifiers [ 0 ] . parent . type === 'VariableDeclarator'
110
140
) {
111
- variableDeclaration = variable . identifiers [ 0 ] . parent ;
141
+ recordVariable ( enclosingFunction , variable . identifiers [ 0 ] . parent ) ;
112
142
}
113
143
}
114
- if ( variableDeclaration === null ) {
115
- return ;
116
- }
117
- if ( ! returnedVariables . has ( enclosingFunction ) ) {
118
- returnedVariables . set ( enclosingFunction , [ ] ) ;
119
- }
120
- returnedVariables . get ( enclosingFunction ) ?. push ( variableDeclaration ) ;
121
144
} ,
122
145
'Program:exit' ( ) {
123
146
const referenceTracker = new ReferenceTracker ( context . sourceCode . scopeManager . globalScope ! ) ;
@@ -174,7 +197,11 @@ export default createRule('prefer-svelte-reactivity', {
174
197
findEnclosingReturn ( node ) !== null ||
175
198
( enclosingPropertyDefinition !== null &&
176
199
( ! ignoreEncapsulatedLocalVariables ||
177
- ! isPropertyEncapsulated ( enclosingPropertyDefinition , returnedVariables ) ) )
200
+ ! isPropertyEncapsulated (
201
+ enclosingPropertyDefinition ,
202
+ returnedFunctionCalls ,
203
+ returnedVariables
204
+ ) ) )
178
205
) {
179
206
context . report ( {
180
207
messageId,
@@ -274,13 +301,23 @@ function isLocalVarEncapsulated(
274
301
function methodReturnsProperty (
275
302
method : TSESTree . MethodDefinition ,
276
303
property : TSESTree . PropertyDefinition ,
304
+ returnedFunctionCalls : Map < FunctionLike , TSESTree . MethodDefinition [ ] > ,
277
305
returnedVariables : Map < FunctionLike , VariableLike [ ] >
278
306
) : boolean {
279
- return returnedVariables . get ( method ) ?. includes ( property ) ?? false ;
307
+ return (
308
+ ( returnedVariables . get ( method ) ?. includes ( property ) ?? false ) ||
309
+ ( returnedFunctionCalls
310
+ . get ( method )
311
+ ?. some ( ( calledFn ) =>
312
+ methodReturnsProperty ( calledFn , property , returnedFunctionCalls , returnedVariables )
313
+ ) ??
314
+ false )
315
+ ) ;
280
316
}
281
317
282
318
function isPropertyEncapsulated (
283
319
node : TSESTree . PropertyDefinition ,
320
+ returnedFunctionCalls : Map < FunctionLike , TSESTree . MethodDefinition [ ] > ,
284
321
returnedVariables : Map < FunctionLike , VariableLike [ ] >
285
322
) : boolean {
286
323
if ( node . accessibility === 'public' ) {
@@ -290,7 +327,7 @@ function isPropertyEncapsulated(
290
327
if (
291
328
classElement . type === 'MethodDefinition' &&
292
329
classElement . accessibility === 'public' &&
293
- methodReturnsProperty ( classElement , node , returnedVariables )
330
+ methodReturnsProperty ( classElement , node , returnedFunctionCalls , returnedVariables )
294
331
) {
295
332
return false ;
296
333
}
0 commit comments