@@ -31,6 +31,10 @@ export default createRule('prefer-svelte-reactivity', {
31
31
]
32
32
} ,
33
33
create ( context ) {
34
+ const returnedVariables : Map <
35
+ TSESTree . ArrowFunctionExpression | TSESTree . FunctionDeclaration ,
36
+ TSESTree . VariableDeclarator [ ]
37
+ > = new Map ( ) ;
34
38
const exportedVars : TSESTree . Node [ ] = [ ] ;
35
39
return {
36
40
...( getSvelteContext ( context ) ?. svelteFileType === '.svelte.[js|ts]' && {
@@ -59,6 +63,28 @@ export default createRule('prefer-svelte-reactivity', {
59
63
}
60
64
}
61
65
} ) ,
66
+ Identifier ( node ) {
67
+ const enclosingReturn = findEnclosingReturn ( node ) ;
68
+ if ( enclosingReturn === null ) {
69
+ return ;
70
+ }
71
+ const enclosingFunction = findEnclosingFunction ( enclosingReturn ) ;
72
+ if ( enclosingFunction === null ) {
73
+ return ;
74
+ }
75
+ const variable = findVariable ( context , node ) ;
76
+ if (
77
+ variable === null ||
78
+ variable . identifiers . length < 1 ||
79
+ variable . identifiers [ 0 ] . parent . type !== 'VariableDeclarator'
80
+ ) {
81
+ return ;
82
+ }
83
+ if ( ! returnedVariables . has ( enclosingFunction ) ) {
84
+ returnedVariables . set ( enclosingFunction , [ ] ) ;
85
+ }
86
+ returnedVariables . get ( enclosingFunction ) ?. push ( variable . identifiers [ 0 ] . parent ) ;
87
+ } ,
62
88
'Program:exit' ( ) {
63
89
const referenceTracker = new ReferenceTracker ( context . sourceCode . scopeManager . globalScope ! ) ;
64
90
for ( const { node, path } of referenceTracker . iterateGlobalReferences ( {
@@ -96,6 +122,20 @@ export default createRule('prefer-svelte-reactivity', {
96
122
} ) ;
97
123
}
98
124
}
125
+ for ( const returnedVar of Array . from ( returnedVariables . values ( ) ) . flat ( ) ) {
126
+ if ( isIn ( node , returnedVar ) ) {
127
+ context . report ( {
128
+ messageId,
129
+ node
130
+ } ) ;
131
+ }
132
+ }
133
+ if ( findEnclosingReturn ( node ) !== null ) {
134
+ context . report ( {
135
+ messageId,
136
+ node
137
+ } ) ;
138
+ }
99
139
if ( path [ 0 ] === 'Date' && isDateMutable ( referenceTracker , node as TSESTree . Expression ) ) {
100
140
context . report ( {
101
141
messageId : 'mutableDateUsed' ,
@@ -135,6 +175,29 @@ export default createRule('prefer-svelte-reactivity', {
135
175
}
136
176
} ) ;
137
177
178
+ function findAncestorOfTypes < T extends string > (
179
+ node : TSESTree . Node ,
180
+ types : string [ ]
181
+ ) : ( TSESTree . Node & { type : T } ) | null {
182
+ if ( types . includes ( node . type ) ) {
183
+ return node as TSESTree . Node & { type : T } ;
184
+ }
185
+ if ( node . parent === undefined || node . parent === null ) {
186
+ return null ;
187
+ }
188
+ return findAncestorOfTypes ( node . parent , types ) ;
189
+ }
190
+
191
+ function findEnclosingReturn ( node : TSESTree . Node ) : TSESTree . ReturnStatement | null {
192
+ return findAncestorOfTypes ( node , [ 'ReturnStatement' ] ) ;
193
+ }
194
+
195
+ function findEnclosingFunction (
196
+ node : TSESTree . Node
197
+ ) : TSESTree . ArrowFunctionExpression | TSESTree . FunctionDeclaration | null {
198
+ return findAncestorOfTypes ( node , [ 'ArrowFunctionExpression' , 'FunctionDeclaration' ] ) ;
199
+ }
200
+
138
201
function isDateMutable ( referenceTracker : ReferenceTracker , ctorNode : TSESTree . Expression ) : boolean {
139
202
return ! referenceTracker
140
203
. iteratePropertyReferences ( ctorNode , {
0 commit comments