1- import type { RuleContext , RuleFeature } from "@eslint-react/kit" ;
2- import type { RuleListener } from "@typescript-eslint/utils/ts-eslint" ;
1+ import type { RuleContext , RuleFeature , RuleSuggest } from "@eslint-react/kit" ;
2+ import type { RuleFixer , RuleListener } from "@typescript-eslint/utils/ts-eslint" ;
33import type { CamelCase } from "string-ts" ;
44import * as ER from "@eslint-react/core" ;
55import { createJsxElementResolver , createRule , findCustomComponentProp } from "../utils" ;
@@ -8,7 +8,11 @@ export const RULE_NAME = "no-missing-button-type";
88
99export const RULE_FEATURES = [ ] as const satisfies RuleFeature [ ] ;
1010
11- export type MessageID = CamelCase < typeof RULE_NAME > ;
11+ export const BUTTON_TYPES = [ "button" , "submit" , "reset" ] as const ;
12+
13+ export type MessageID =
14+ | CamelCase < typeof RULE_NAME >
15+ | "addButtonType" ;
1216
1317export default createRule < [ ] , MessageID > ( {
1418 meta : {
@@ -17,7 +21,9 @@ export default createRule<[], MessageID>({
1721 description : "Enforces explicit `type` attribute for `button` elements." ,
1822 [ Symbol . for ( "rule_features" ) ] : RULE_FEATURES ,
1923 } ,
24+ hasSuggestions : true ,
2025 messages : {
26+ addButtonType : "Add 'type' attribute with value '{{type}}'." ,
2127 noMissingButtonType : "Add missing 'type' attribute on 'button' component." ,
2228 } ,
2329 schema : [ ] ,
@@ -51,6 +57,9 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
5157 context . report ( {
5258 messageId : "noMissingButtonType" ,
5359 node : attributeNode ,
60+ suggest : getSuggest ( ( type ) => ( fixer : RuleFixer ) => {
61+ return fixer . replaceText ( node , `${ propNameOnJsx } ="${ type } "` ) ;
62+ } ) ,
5463 } ) ;
5564 }
5665 return ;
@@ -59,8 +68,21 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
5968 context . report ( {
6069 messageId : "noMissingButtonType" ,
6170 node,
71+ suggest : getSuggest ( ( type ) => ( fixer : RuleFixer ) => {
72+ const lastToken = context . sourceCode . getLastToken ( node . openingElement ) ;
73+ if ( lastToken == null ) return null ;
74+ return fixer . insertTextBefore ( lastToken , ` type="${ type } "` ) ;
75+ } ) ,
6276 } ) ;
6377 }
6478 } ,
6579 } ;
6680}
81+
82+ function getSuggest ( getFix : ( type : string ) => RuleSuggest [ "fix" ] ) : RuleSuggest < MessageID > [ ] {
83+ return BUTTON_TYPES . map ( ( type ) => ( {
84+ messageId : "addButtonType" ,
85+ data : { type } ,
86+ fix : getFix ( type ) ,
87+ } ) ) ;
88+ }
0 commit comments