11import type { TSESTree } from '@typescript-eslint/types' ;
2+ import type { Variable } from '@typescript-eslint/scope-manager' ;
23import { createRule } from '../utils/index.js' ;
34import type { RuleContext } from '../types.js' ;
45import { extractStoreReferences } from './reference-helpers/svelte-store.js' ;
56import { getSourceCode } from '../utils/compat.js' ;
67
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+
734export default createRule ( 'derived-has-same-inputs-outputs' , {
835 meta : {
936 docs : {
@@ -12,10 +39,11 @@ export default createRule('derived-has-same-inputs-outputs', {
1239 recommended : false ,
1340 conflictWithPrettier : false
1441 } ,
15- fixable : 'code' ,
42+ hasSuggestions : true ,
1643 schema : [ ] ,
1744 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}}.'
1947 } ,
2048 type : 'suggestion'
2149 } ,
@@ -51,24 +79,35 @@ export default createRule('derived-has-same-inputs-outputs', {
5179 if ( fnParam . type !== 'Identifier' ) return ;
5280 const expectedName = `$${ args . name } ` ;
5381 if ( expectedName !== fnParam . name ) {
82+ const { hasConflict, variable } = findVariableForName (
83+ context ,
84+ fn . body ,
85+ fnParam . name ,
86+ expectedName
87+ ) ;
88+
5489 context . report ( {
5590 node : fn ,
5691 loc : fnParam . loc ,
5792 messageId : 'unexpected' ,
5893 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 ) ;
62102
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+ ]
72111 } ) ;
73112 }
74113 }
@@ -92,23 +131,35 @@ export default createRule('derived-has-same-inputs-outputs', {
92131 if ( element && element . type === 'Identifier' && argName ) {
93132 const expectedName = `$${ argName } ` ;
94133 if ( expectedName !== element . name ) {
134+ const { hasConflict, variable } = findVariableForName (
135+ context ,
136+ fn . body ,
137+ element . name ,
138+ expectedName
139+ ) ;
140+
95141 context . report ( {
96142 node : fn ,
97143 loc : element . loc ,
98144 messageId : 'unexpected' ,
99145 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 ) ;
105154
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+ ]
112163 } ) ;
113164 }
114165 }
0 commit comments