Skip to content

Commit 54b40df

Browse files
authored
feat: add suggest to 'react-x/no-missing-button-type' (#1136)
1 parent 52b0851 commit 54b40df

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

packages/plugins/eslint-plugin-react-dom/src/rules/no-missing-button-type.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ ruleTester.run(RULE_NAME, rule, {
1010
errors: [
1111
{
1212
messageId: "noMissingButtonType",
13+
suggestions: [
14+
{
15+
messageId: "addButtonType",
16+
data: { type: "button" },
17+
output: tsx`<button type="button">Click me</button>;`,
18+
},
19+
{
20+
messageId: "addButtonType",
21+
data: { type: "submit" },
22+
output: tsx`<button type="submit">Click me</button>;`,
23+
},
24+
{
25+
messageId: "addButtonType",
26+
data: { type: "reset" },
27+
output: tsx`<button type="reset">Click me</button>;`,
28+
},
29+
],
1330
},
1431
],
1532
},
@@ -18,6 +35,23 @@ ruleTester.run(RULE_NAME, rule, {
1835
errors: [
1936
{
2037
messageId: "noMissingButtonType",
38+
suggestions: [
39+
{
40+
messageId: "addButtonType",
41+
data: { type: "button" },
42+
output: tsx`<PolyComponent as="button" type="button">Click me</PolyComponent>;`,
43+
},
44+
{
45+
messageId: "addButtonType",
46+
data: { type: "submit" },
47+
output: tsx`<PolyComponent as="button" type="submit">Click me</PolyComponent>;`,
48+
},
49+
{
50+
messageId: "addButtonType",
51+
data: { type: "reset" },
52+
output: tsx`<PolyComponent as="button" type="reset">Click me</PolyComponent>;`,
53+
},
54+
],
2155
},
2256
],
2357
settings: {

packages/plugins/eslint-plugin-react-dom/src/rules/no-missing-button-type.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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";
33
import type { CamelCase } from "string-ts";
44
import * as ER from "@eslint-react/core";
55
import { createJsxElementResolver, createRule, findCustomComponentProp } from "../utils";
@@ -8,7 +8,11 @@ export const RULE_NAME = "no-missing-button-type";
88

99
export 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

1317
export 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+
}

packages/utilities/kit/src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ export type RuleFeature =
4444
| "EXP"; // Experimental
4545

4646
export type RulePolicy = number;
47+
48+
export type RuleSuggest<MessageIds extends string = string> = {
49+
messageId: MessageIds;
50+
data?: Record<string, unknown>;
51+
fix: tseslint.ReportFixFunction;
52+
};

0 commit comments

Comments
 (0)