1
1
import type { TSESTree } from '@typescript-eslint/types' ;
2
+ import type { Variable } from '@typescript-eslint/scope-manager' ;
2
3
import { createRule } from '../utils/index.js' ;
3
4
import type { RuleContext } from '../types.js' ;
4
5
import { extractStoreReferences } from './reference-helpers/svelte-store.js' ;
5
6
import { getSourceCode } from '../utils/compat.js' ;
6
7
8
+ function findVariableForName (
9
+ context : RuleContext ,
10
+ node : TSESTree . Node ,
11
+ name : string ,
12
+ expectedName : string
13
+ ) : { hasConflict : boolean ; variable : Variable | null } {
14
+ const scope = getSourceCode ( context ) . getScope ( node ) ;
15
+ let hasConflict = false ;
16
+ let variable : Variable | null = null ;
17
+
18
+ for ( const v of scope . variables ) {
19
+ if ( hasConflict && variable ) {
20
+ break ;
21
+ }
22
+ if ( v . name === expectedName ) {
23
+ hasConflict = true ;
24
+ continue ;
25
+ }
26
+ if ( v . name === name ) {
27
+ variable = v ;
28
+ }
29
+ }
30
+
31
+ return { hasConflict, variable } ;
32
+ }
33
+
7
34
export default createRule ( 'derived-has-same-inputs-outputs' , {
8
35
meta : {
9
36
docs : {
@@ -12,10 +39,11 @@ export default createRule('derived-has-same-inputs-outputs', {
12
39
recommended : false ,
13
40
conflictWithPrettier : false
14
41
} ,
15
- fixable : 'code' ,
42
+ hasSuggestions : true ,
16
43
schema : [ ] ,
17
44
messages : {
18
- unexpected : "The argument name should be '{{name}}'."
45
+ unexpected : "The argument name should be '{{name}}'." ,
46
+ renameParam : 'Rename the parameter from {{oldName}} to {{newName}}.'
19
47
} ,
20
48
type : 'suggestion'
21
49
} ,
@@ -51,24 +79,35 @@ export default createRule('derived-has-same-inputs-outputs', {
51
79
if ( fnParam . type !== 'Identifier' ) return ;
52
80
const expectedName = `$${ args . name } ` ;
53
81
if ( expectedName !== fnParam . name ) {
82
+ const { hasConflict, variable } = findVariableForName (
83
+ context ,
84
+ fn . body ,
85
+ fnParam . name ,
86
+ expectedName
87
+ ) ;
88
+
54
89
context . report ( {
55
90
node : fn ,
56
91
loc : fnParam . loc ,
57
92
messageId : 'unexpected' ,
58
93
data : { name : expectedName } ,
59
- fix : ( fixer ) => {
60
- const scope = getSourceCode ( context ) . getScope ( fn . body ) ;
61
- const variable = scope . variables . find ( ( variable ) => variable . name === fnParam . name ) ;
94
+ suggest : hasConflict
95
+ ? undefined
96
+ : [
97
+ {
98
+ messageId : 'renameParam' ,
99
+ data : { oldName : fnParam . name , newName : expectedName } ,
100
+ * fix ( fixer ) {
101
+ yield fixer . replaceText ( fnParam , expectedName ) ;
62
102
63
- if ( ! variable ) {
64
- return fixer . replaceText ( fnParam , expectedName ) ;
65
- }
66
-
67
- return [
68
- fixer . replaceText ( fnParam , expectedName ) ,
69
- ...variable . references . map ( ( ref ) => fixer . replaceText ( ref . identifier , expectedName ) )
70
- ] ;
71
- }
103
+ if ( variable ) {
104
+ for ( const ref of variable . references ) {
105
+ yield fixer . replaceText ( ref . identifier , expectedName ) ;
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ]
72
111
} ) ;
73
112
}
74
113
}
@@ -92,23 +131,35 @@ export default createRule('derived-has-same-inputs-outputs', {
92
131
if ( element && element . type === 'Identifier' && argName ) {
93
132
const expectedName = `$${ argName } ` ;
94
133
if ( expectedName !== element . name ) {
134
+ const { hasConflict, variable } = findVariableForName (
135
+ context ,
136
+ fn . body ,
137
+ element . name ,
138
+ expectedName
139
+ ) ;
140
+
95
141
context . report ( {
96
142
node : fn ,
97
143
loc : element . loc ,
98
144
messageId : 'unexpected' ,
99
145
data : { name : expectedName } ,
100
- * fix ( fixer ) {
101
- const scope = getSourceCode ( context ) . getScope ( fn . body ) ;
102
- const variable = scope . variables . find ( ( variable ) => variable . name === element . name ) ;
103
-
104
- yield fixer . replaceText ( element , expectedName ) ;
146
+ suggest : hasConflict
147
+ ? undefined
148
+ : [
149
+ {
150
+ messageId : 'renameParam' ,
151
+ data : { oldName : element . name , newName : expectedName } ,
152
+ * fix ( fixer ) {
153
+ yield fixer . replaceText ( element , expectedName ) ;
105
154
106
- if ( variable ) {
107
- for ( const ref of variable . references ) {
108
- yield fixer . replaceText ( ref . identifier , expectedName ) ;
109
- }
110
- }
111
- }
155
+ if ( variable ) {
156
+ for ( const ref of variable . references ) {
157
+ yield fixer . replaceText ( ref . identifier , expectedName ) ;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ ]
112
163
} ) ;
113
164
}
114
165
}
0 commit comments